diff --git a/3rdParty/metis/metis-5.1.0/CMakeLists.txt b/3rdParty/metis/metis-5.1.0/CMakeLists.txt deleted file mode 100644 index 967b473efd489422655ccd8b031feaa8db47f3a6..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project(METIS) - -set(GKLIB_PATH "${PROJECT_SOURCE_DIR}/GKlib" CACHE PATH "path to GKlib") -#set(SHARED FALSE CACHE BOOL "build a shared library") - -if(MSVC) - set(METIS_INSTALL FALSE) -else() - set(METIS_INSTALL TRUE) -endif() - -# Configure libmetis library. -if(BUILD_SHARED_LIBS) - set(METIS_LIBRARY_TYPE SHARED) -else() - set(METIS_LIBRARY_TYPE STATIC) -endif() - -include(${GKLIB_PATH}/GKlibSystem.cmake) -# Add include directories. -include_directories(${GKLIB_PATH}) -include_directories(include) -# Recursively look for CMakeLists.txt in subdirs. -add_subdirectory("include") -add_subdirectory("libmetis") -#add_subdirectory("programs") diff --git a/3rdParty/metis/metis-5.1.0/GKlib/BUILD.txt b/3rdParty/metis/metis-5.1.0/GKlib/BUILD.txt deleted file mode 100644 index cdb9987a9e8c93e1b6ef101a5db55c014963e703..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/BUILD.txt +++ /dev/null @@ -1,25 +0,0 @@ -Building GKlib requires CMake 2.8. Once you've installed CMake run - - $ make - -This will build the GKlib library in build/<arch>/. Options can be tweaked by -running make config. For example, - - $ make config openmp=ON - $ make - -will build GKlib will OpenMP support if it is available. - -GKlib can be installed with - - $ make install - -and uninstalled with - - $ make uninstall - -You can choose the installation prefix with make config: - - $ make config prefix=~/local - -will cause GKlib to be install in the ~/local tree. diff --git a/3rdParty/metis/metis-5.1.0/GKlib/CMakeLists.txt b/3rdParty/metis/metis-5.1.0/GKlib/CMakeLists.txt deleted file mode 100644 index 67b600aa6c3313d50ae7792a333fd829e29c3dd5..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project(GKlib) - -get_filename_component(abs "." ABSOLUTE) -set(GKLIB_PATH ${abs}) -unset(abs) -include(GKlibSystem.cmake) - -include_directories(".") -add_library(GKlib STATIC ${GKlib_sources}) -if(UNIX) - target_link_libraries(GKlib m) -endif(UNIX) - -include_directories("test") -add_subdirectory("test") - -install(TARGETS GKlib - ARCHIVE DESTINATION lib - LIBRARY DESTINATION lib) -install(FILES ${GKlib_includes} DESTINATION include) diff --git a/3rdParty/metis/metis-5.1.0/GKlib/csr.c b/3rdParty/metis/metis-5.1.0/GKlib/csr.c deleted file mode 100644 index a19d793bdcecd7c4b8bfa2d9109475a1c31c061b..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/csr.c +++ /dev/null @@ -1,2010 +0,0 @@ -/*! - * \file - * - * \brief Various routines with dealing with CSR matrices - * - * \author George Karypis - * \version\verbatim $Id: csr.c 13437 2013-01-11 21:54:10Z karypis $ \endverbatim - */ - -#include <GKlib.h> - -#define OMPMINOPS 50000 - -/*************************************************************************/ -/*! Allocate memory for a CSR matrix and initializes it - \returns the allocated matrix. The various fields are set to NULL. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_Create() -{ - gk_csr_t *mat; - - mat = (gk_csr_t *)gk_malloc(sizeof(gk_csr_t), "gk_csr_Create: mat"); - - gk_csr_Init(mat); - - return mat; -} - - -/*************************************************************************/ -/*! Initializes the matrix - \param mat is the matrix to be initialized. -*/ -/*************************************************************************/ -void gk_csr_Init(gk_csr_t *mat) -{ - memset(mat, 0, sizeof(gk_csr_t)); - mat->nrows = mat->ncols = -1; -} - - -/*************************************************************************/ -/*! Frees all the memory allocated for matrix. - \param mat is the matrix to be freed. -*/ -/*************************************************************************/ -void gk_csr_Free(gk_csr_t **mat) -{ - if (*mat == NULL) - return; - gk_csr_FreeContents(*mat); - gk_free((void **)mat, LTERM); -} - - -/*************************************************************************/ -/*! Frees only the memory allocated for the matrix's different fields and - sets them to NULL. - \param mat is the matrix whose contents will be freed. -*/ -/*************************************************************************/ -void gk_csr_FreeContents(gk_csr_t *mat) -{ - gk_free((void *)&mat->rowptr, &mat->rowind, &mat->rowval, &mat->rowids, - &mat->colptr, &mat->colind, &mat->colval, &mat->colids, - &mat->rnorms, &mat->cnorms, &mat->rsums, &mat->csums, - &mat->rsizes, &mat->csizes, &mat->rvols, &mat->cvols, - &mat->rwgts, &mat->cwgts, - LTERM); -} - - -/*************************************************************************/ -/*! Returns a copy of a matrix. - \param mat is the matrix to be duplicated. - \returns the newly created copy of the matrix. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_Dup(gk_csr_t *mat) -{ - gk_csr_t *nmat; - - nmat = gk_csr_Create(); - - nmat->nrows = mat->nrows; - nmat->ncols = mat->ncols; - - /* copy the row structure */ - if (mat->rowptr) - nmat->rowptr = gk_zcopy(mat->nrows+1, mat->rowptr, - gk_zmalloc(mat->nrows+1, "gk_csr_Dup: rowptr")); - if (mat->rowids) - nmat->rowids = gk_icopy(mat->nrows, mat->rowids, - gk_imalloc(mat->nrows, "gk_csr_Dup: rowids")); - if (mat->rnorms) - nmat->rnorms = gk_fcopy(mat->nrows, mat->rnorms, - gk_fmalloc(mat->nrows, "gk_csr_Dup: rnorms")); - if (mat->rowind) - nmat->rowind = gk_icopy(mat->rowptr[mat->nrows], mat->rowind, - gk_imalloc(mat->rowptr[mat->nrows], "gk_csr_Dup: rowind")); - if (mat->rowval) - nmat->rowval = gk_fcopy(mat->rowptr[mat->nrows], mat->rowval, - gk_fmalloc(mat->rowptr[mat->nrows], "gk_csr_Dup: rowval")); - - /* copy the col structure */ - if (mat->colptr) - nmat->colptr = gk_zcopy(mat->ncols+1, mat->colptr, - gk_zmalloc(mat->ncols+1, "gk_csr_Dup: colptr")); - if (mat->colids) - nmat->colids = gk_icopy(mat->ncols, mat->colids, - gk_imalloc(mat->ncols, "gk_csr_Dup: colids")); - if (mat->cnorms) - nmat->cnorms = gk_fcopy(mat->ncols, mat->cnorms, - gk_fmalloc(mat->ncols, "gk_csr_Dup: cnorms")); - if (mat->colind) - nmat->colind = gk_icopy(mat->colptr[mat->ncols], mat->colind, - gk_imalloc(mat->colptr[mat->ncols], "gk_csr_Dup: colind")); - if (mat->colval) - nmat->colval = gk_fcopy(mat->colptr[mat->ncols], mat->colval, - gk_fmalloc(mat->colptr[mat->ncols], "gk_csr_Dup: colval")); - - return nmat; -} - - -/*************************************************************************/ -/*! Returns a submatrix containint a set of consecutive rows. - \param mat is the original matrix. - \param rstart is the starting row. - \param nrows is the number of rows from rstart to extract. - \returns the row structure of the newly created submatrix. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_ExtractSubmatrix(gk_csr_t *mat, int rstart, int nrows) -{ - ssize_t i; - gk_csr_t *nmat; - - if (rstart+nrows > mat->nrows) - return NULL; - - nmat = gk_csr_Create(); - - nmat->nrows = nrows; - nmat->ncols = mat->ncols; - - /* copy the row structure */ - if (mat->rowptr) - nmat->rowptr = gk_zcopy(nrows+1, mat->rowptr+rstart, - gk_zmalloc(nrows+1, "gk_csr_ExtractSubmatrix: rowptr")); - for (i=nrows; i>=0; i--) - nmat->rowptr[i] -= nmat->rowptr[0]; - ASSERT(nmat->rowptr[0] == 0); - - if (mat->rowids) - nmat->rowids = gk_icopy(nrows, mat->rowids+rstart, - gk_imalloc(nrows, "gk_csr_ExtractSubmatrix: rowids")); - if (mat->rnorms) - nmat->rnorms = gk_fcopy(nrows, mat->rnorms+rstart, - gk_fmalloc(nrows, "gk_csr_ExtractSubmatrix: rnorms")); - - if (mat->rsums) - nmat->rsums = gk_fcopy(nrows, mat->rsums+rstart, - gk_fmalloc(nrows, "gk_csr_ExtractSubmatrix: rsums")); - - ASSERT(nmat->rowptr[nrows] == mat->rowptr[rstart+nrows]-mat->rowptr[rstart]); - if (mat->rowind) - nmat->rowind = gk_icopy(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], - mat->rowind+mat->rowptr[rstart], - gk_imalloc(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], - "gk_csr_ExtractSubmatrix: rowind")); - if (mat->rowval) - nmat->rowval = gk_fcopy(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], - mat->rowval+mat->rowptr[rstart], - gk_fmalloc(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], - "gk_csr_ExtractSubmatrix: rowval")); - - return nmat; -} - - -/*************************************************************************/ -/*! Returns a submatrix containing a certain set of rows. - \param mat is the original matrix. - \param nrows is the number of rows to extract. - \param rind is the set of row numbers to extract. - \returns the row structure of the newly created submatrix. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_ExtractRows(gk_csr_t *mat, int nrows, int *rind) -{ - ssize_t i, ii, j, nnz; - gk_csr_t *nmat; - - nmat = gk_csr_Create(); - - nmat->nrows = nrows; - nmat->ncols = mat->ncols; - - for (nnz=0, i=0; i<nrows; i++) - nnz += mat->rowptr[rind[i]+1]-mat->rowptr[rind[i]]; - - nmat->rowptr = gk_zmalloc(nmat->nrows+1, "gk_csr_ExtractPartition: rowptr"); - nmat->rowind = gk_imalloc(nnz, "gk_csr_ExtractPartition: rowind"); - nmat->rowval = gk_fmalloc(nnz, "gk_csr_ExtractPartition: rowval"); - - nmat->rowptr[0] = 0; - for (nnz=0, j=0, ii=0; ii<nrows; ii++) { - i = rind[ii]; - gk_icopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowind+mat->rowptr[i], nmat->rowind+nnz); - gk_fcopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowval+mat->rowptr[i], nmat->rowval+nnz); - nnz += mat->rowptr[i+1]-mat->rowptr[i]; - nmat->rowptr[++j] = nnz; - } - ASSERT(j == nmat->nrows); - - return nmat; -} - - -/*************************************************************************/ -/*! Returns a submatrix corresponding to a specified partitioning of rows. - \param mat is the original matrix. - \param part is the partitioning vector of the rows. - \param pid is the partition ID that will be extracted. - \returns the row structure of the newly created submatrix. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_ExtractPartition(gk_csr_t *mat, int *part, int pid) -{ - ssize_t i, j, nnz; - gk_csr_t *nmat; - - nmat = gk_csr_Create(); - - nmat->nrows = 0; - nmat->ncols = mat->ncols; - - for (nnz=0, i=0; i<mat->nrows; i++) { - if (part[i] == pid) { - nmat->nrows++; - nnz += mat->rowptr[i+1]-mat->rowptr[i]; - } - } - - nmat->rowptr = gk_zmalloc(nmat->nrows+1, "gk_csr_ExtractPartition: rowptr"); - nmat->rowind = gk_imalloc(nnz, "gk_csr_ExtractPartition: rowind"); - nmat->rowval = gk_fmalloc(nnz, "gk_csr_ExtractPartition: rowval"); - - nmat->rowptr[0] = 0; - for (nnz=0, j=0, i=0; i<mat->nrows; i++) { - if (part[i] == pid) { - gk_icopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowind+mat->rowptr[i], nmat->rowind+nnz); - gk_fcopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowval+mat->rowptr[i], nmat->rowval+nnz); - nnz += mat->rowptr[i+1]-mat->rowptr[i]; - nmat->rowptr[++j] = nnz; - } - } - ASSERT(j == nmat->nrows); - - return nmat; -} - - -/*************************************************************************/ -/*! Splits the matrix into multiple sub-matrices based on the provided - color array. - \param mat is the original matrix. - \param color is an array of size equal to the number of non-zeros - in the matrix (row-wise structure). The matrix is split into - as many parts as the number of colors. For meaningfull results, - the colors should be numbered consecutively starting from 0. - \returns an array of matrices for each supplied color number. -*/ -/**************************************************************************/ -gk_csr_t **gk_csr_Split(gk_csr_t *mat, int *color) -{ - ssize_t i, j; - int nrows, ncolors; - ssize_t *rowptr; - int *rowind; - float *rowval; - gk_csr_t **smats; - - nrows = mat->nrows; - rowptr = mat->rowptr; - rowind = mat->rowind; - rowval = mat->rowval; - - ncolors = gk_imax(rowptr[nrows], color)+1; - - smats = (gk_csr_t **)gk_malloc(sizeof(gk_csr_t *)*ncolors, "gk_csr_Split: smats"); - for (i=0; i<ncolors; i++) { - smats[i] = gk_csr_Create(); - smats[i]->nrows = mat->nrows; - smats[i]->ncols = mat->ncols; - smats[i]->rowptr = gk_zsmalloc(nrows+1, 0, "gk_csr_Split: smats[i]->rowptr"); - } - - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) - smats[color[j]]->rowptr[i]++; - } - for (i=0; i<ncolors; i++) - MAKECSR(j, nrows, smats[i]->rowptr); - - for (i=0; i<ncolors; i++) { - smats[i]->rowind = gk_imalloc(smats[i]->rowptr[nrows], "gk_csr_Split: smats[i]->rowind"); - smats[i]->rowval = gk_fmalloc(smats[i]->rowptr[nrows], "gk_csr_Split: smats[i]->rowval"); - } - - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - smats[color[j]]->rowind[smats[color[j]]->rowptr[i]] = rowind[j]; - smats[color[j]]->rowval[smats[color[j]]->rowptr[i]] = rowval[j]; - smats[color[j]]->rowptr[i]++; - } - } - - for (i=0; i<ncolors; i++) - SHIFTCSR(j, nrows, smats[i]->rowptr); - - return smats; -} - - -/**************************************************************************/ -/*! Reads a CSR matrix from the supplied file and stores it the matrix's - forward structure. - \param filename is the file that stores the data. - \param format is either GK_CSR_FMT_METIS, GK_CSR_FMT_CLUTO, - GK_CSR_FMT_CSR, GK_CSR_FMT_BINROW, GK_CSR_FMT_BINCOL - specifying the type of the input format. - The GK_CSR_FMT_CSR does not contain a header - line, whereas the GK_CSR_FMT_BINROW is a binary format written - by gk_csr_Write() using the same format specifier. - \param readvals is either 1 or 0, indicating if the CSR file contains - values or it does not. It only applies when GK_CSR_FMT_CSR is - used. - \param numbering is either 1 or 0, indicating if the numbering of the - indices start from 1 or 0, respectively. If they start from 1, - they are automatically decreamented during input so that they - will start from 0. It only applies when GK_CSR_FMT_CSR is - used. - \returns the matrix that was read. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_Read(char *filename, int format, int readvals, int numbering) -{ - ssize_t i, k, l; - size_t nfields, nrows, ncols, nnz, fmt, ncon; - size_t lnlen; - ssize_t *rowptr; - int *rowind, ival; - float *rowval=NULL, fval; - int readsizes, readwgts; - char *line=NULL, *head, *tail, fmtstr[256]; - FILE *fpin; - gk_csr_t *mat=NULL; - - - if (!gk_fexists(filename)) - gk_errexit(SIGERR, "File %s does not exist!\n", filename); - - if (format == GK_CSR_FMT_BINROW) { - mat = gk_csr_Create(); - - fpin = gk_fopen(filename, "rb", "gk_csr_Read: fpin"); - if (fread(&(mat->nrows), sizeof(int32_t), 1, fpin) != 1) - gk_errexit(SIGERR, "Failed to read the nrows from file %s!\n", filename); - if (fread(&(mat->ncols), sizeof(int32_t), 1, fpin) != 1) - gk_errexit(SIGERR, "Failed to read the ncols from file %s!\n", filename); - mat->rowptr = gk_zmalloc(mat->nrows+1, "gk_csr_Read: rowptr"); - if (fread(mat->rowptr, sizeof(ssize_t), mat->nrows+1, fpin) != mat->nrows+1) - gk_errexit(SIGERR, "Failed to read the rowptr from file %s!\n", filename); - mat->rowind = gk_imalloc(mat->rowptr[mat->nrows], "gk_csr_Read: rowind"); - if (fread(mat->rowind, sizeof(int32_t), mat->rowptr[mat->nrows], fpin) != mat->rowptr[mat->nrows]) - gk_errexit(SIGERR, "Failed to read the rowind from file %s!\n", filename); - if (readvals == 1) { - mat->rowval = gk_fmalloc(mat->rowptr[mat->nrows], "gk_csr_Read: rowval"); - if (fread(mat->rowval, sizeof(float), mat->rowptr[mat->nrows], fpin) != mat->rowptr[mat->nrows]) - gk_errexit(SIGERR, "Failed to read the rowval from file %s!\n", filename); - } - - gk_fclose(fpin); - return mat; - } - - if (format == GK_CSR_FMT_BINCOL) { - mat = gk_csr_Create(); - - fpin = gk_fopen(filename, "rb", "gk_csr_Read: fpin"); - if (fread(&(mat->nrows), sizeof(int32_t), 1, fpin) != 1) - gk_errexit(SIGERR, "Failed to read the nrows from file %s!\n", filename); - if (fread(&(mat->ncols), sizeof(int32_t), 1, fpin) != 1) - gk_errexit(SIGERR, "Failed to read the ncols from file %s!\n", filename); - mat->colptr = gk_zmalloc(mat->ncols+1, "gk_csr_Read: colptr"); - if (fread(mat->colptr, sizeof(ssize_t), mat->ncols+1, fpin) != mat->ncols+1) - gk_errexit(SIGERR, "Failed to read the colptr from file %s!\n", filename); - mat->colind = gk_imalloc(mat->colptr[mat->ncols], "gk_csr_Read: colind"); - if (fread(mat->colind, sizeof(int32_t), mat->colptr[mat->ncols], fpin) != mat->colptr[mat->ncols]) - gk_errexit(SIGERR, "Failed to read the colind from file %s!\n", filename); - if (readvals) { - mat->colval = gk_fmalloc(mat->colptr[mat->ncols], "gk_csr_Read: colval"); - if (fread(mat->colval, sizeof(float), mat->colptr[mat->ncols], fpin) != mat->colptr[mat->ncols]) - gk_errexit(SIGERR, "Failed to read the colval from file %s!\n", filename); - } - - gk_fclose(fpin); - return mat; - } - - - if (format == GK_CSR_FMT_CLUTO) { - fpin = gk_fopen(filename, "r", "gk_csr_Read: fpin"); - do { - if (gk_getline(&line, &lnlen, fpin) <= 0) - gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename); - } while (line[0] == '%'); - - if (sscanf(line, "%zu %zu %zu", &nrows, &ncols, &nnz) != 3) - gk_errexit(SIGERR, "Header line must contain 3 integers.\n"); - - readsizes = 0; - readwgts = 0; - readvals = 1; - numbering = 1; - } - else if (format == GK_CSR_FMT_METIS) { - fpin = gk_fopen(filename, "r", "gk_csr_Read: fpin"); - do { - if (gk_getline(&line, &lnlen, fpin) <= 0) - gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename); - } while (line[0] == '%'); - - fmt = ncon = 0; - nfields = sscanf(line, "%zu %zu %zu %zu", &nrows, &nnz, &fmt, &ncon); - if (nfields < 2) - gk_errexit(SIGERR, "Header line must contain at least 2 integers (#vtxs and #edges).\n"); - - ncols = nrows; - nnz *= 2; - - if (fmt > 111) - gk_errexit(SIGERR, "Cannot read this type of file format [fmt=%zu]!\n", fmt); - - sprintf(fmtstr, "%03zu", fmt%1000); - readsizes = (fmtstr[0] == '1'); - readwgts = (fmtstr[1] == '1'); - readvals = (fmtstr[2] == '1'); - numbering = 1; - ncon = (ncon == 0 ? 1 : ncon); - } - else { - readsizes = 0; - readwgts = 0; - - gk_getfilestats(filename, &nrows, &nnz, NULL, NULL); - - if (readvals == 1 && nnz%2 == 1) - gk_errexit(SIGERR, "Error: The number of numbers (%zd %d) in the input file is not even.\n", nnz, readvals); - if (readvals == 1) - nnz = nnz/2; - fpin = gk_fopen(filename, "r", "gk_csr_Read: fpin"); - } - - mat = gk_csr_Create(); - - mat->nrows = nrows; - - rowptr = mat->rowptr = gk_zmalloc(nrows+1, "gk_csr_Read: rowptr"); - rowind = mat->rowind = gk_imalloc(nnz, "gk_csr_Read: rowind"); - if (readvals != 2) - rowval = mat->rowval = gk_fsmalloc(nnz, 1.0, "gk_csr_Read: rowval"); - - if (readsizes) - mat->rsizes = gk_fsmalloc(nrows, 0.0, "gk_csr_Read: rsizes"); - - if (readwgts) - mat->rwgts = gk_fsmalloc(nrows*ncon, 0.0, "gk_csr_Read: rwgts"); - - /*---------------------------------------------------------------------- - * Read the sparse matrix file - *---------------------------------------------------------------------*/ - numbering = (numbering ? - 1 : 0); - for (ncols=0, rowptr[0]=0, k=0, i=0; i<nrows; i++) { - do { - if (gk_getline(&line, &lnlen, fpin) == -1) - gk_errexit(SIGERR, "Premature end of input file: file while reading row %d\n", i); - } while (line[0] == '%'); - - head = line; - tail = NULL; - - /* Read vertex sizes */ - if (readsizes) { -#ifdef __MSC__ - mat->rsizes[i] = (float)strtod(head, &tail); -#else - mat->rsizes[i] = strtof(head, &tail); -#endif - if (tail == head) - gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1); - if (mat->rsizes[i] < 0) - errexit("The size for vertex %zd must be >= 0\n", i+1); - head = tail; - } - - /* Read vertex weights */ - if (readwgts) { - for (l=0; l<ncon; l++) { -#ifdef __MSC__ - mat->rwgts[i*ncon+l] = (float)strtod(head, &tail); -#else - mat->rwgts[i*ncon+l] = strtof(head, &tail); -#endif - if (tail == head) - errexit("The line for vertex %zd does not have enough weights " - "for the %d constraints.\n", i+1, ncon); - if (mat->rwgts[i*ncon+l] < 0) - errexit("The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l); - head = tail; - } - } - - - /* Read the rest of the row */ - while (1) { - ival = (int)strtol(head, &tail, 0); - if (tail == head) - break; - head = tail; - - if ((rowind[k] = ival + numbering) < 0) - gk_errexit(SIGERR, "Error: Invalid column number %d at row %zd.\n", ival, i); - - ncols = gk_max(rowind[k], ncols); - - if (readvals == 1) { -#ifdef __MSC__ - fval = (float)strtod(head, &tail); -#else - fval = strtof(head, &tail); -#endif - if (tail == head) - gk_errexit(SIGERR, "Value could not be found for column! Row:%zd, NNZ:%zd\n", i, k); - head = tail; - - rowval[k] = fval; - } - k++; - } - rowptr[i+1] = k; - } - - if (format == GK_CSR_FMT_METIS) { - ASSERT(ncols+1 == mat->nrows); - mat->ncols = mat->nrows; - } - else { - mat->ncols = ncols+1; - } - - if (k != nnz) - gk_errexit(SIGERR, "gk_csr_Read: Something wrong with the number of nonzeros in " - "the input file. NNZ=%zd, ActualNNZ=%zd.\n", nnz, k); - - gk_fclose(fpin); - - gk_free((void **)&line, LTERM); - - return mat; -} - - -/**************************************************************************/ -/*! Writes the row-based structure of a matrix into a file. - \param mat is the matrix to be written, - \param filename is the name of the output file. - \param format is one of: GK_CSR_FMT_CLUTO, GK_CSR_FMT_CSR, - GK_CSR_FMT_BINROW, GK_CSR_FMT_BINCOL. - \param writevals is either 1 or 0 indicating if the values will be - written or not. This is only applicable when GK_CSR_FMT_CSR - is used. - \param numbering is either 1 or 0 indicating if the internal 0-based - numbering will be shifted by one or not during output. This - is only applicable when GK_CSR_FMT_CSR is used. -*/ -/**************************************************************************/ -void gk_csr_Write(gk_csr_t *mat, char *filename, int format, int writevals, int numbering) -{ - ssize_t i, j; - FILE *fpout; - - if (format == GK_CSR_FMT_BINROW) { - if (filename == NULL) - gk_errexit(SIGERR, "The filename parameter cannot be NULL.\n"); - fpout = gk_fopen(filename, "wb", "gk_csr_Write: fpout"); - - fwrite(&(mat->nrows), sizeof(int32_t), 1, fpout); - fwrite(&(mat->ncols), sizeof(int32_t), 1, fpout); - fwrite(mat->rowptr, sizeof(ssize_t), mat->nrows+1, fpout); - fwrite(mat->rowind, sizeof(int32_t), mat->rowptr[mat->nrows], fpout); - if (writevals) - fwrite(mat->rowval, sizeof(float), mat->rowptr[mat->nrows], fpout); - - gk_fclose(fpout); - return; - } - - if (format == GK_CSR_FMT_BINCOL) { - if (filename == NULL) - gk_errexit(SIGERR, "The filename parameter cannot be NULL.\n"); - fpout = gk_fopen(filename, "wb", "gk_csr_Write: fpout"); - - fwrite(&(mat->nrows), sizeof(int32_t), 1, fpout); - fwrite(&(mat->ncols), sizeof(int32_t), 1, fpout); - fwrite(mat->colptr, sizeof(ssize_t), mat->ncols+1, fpout); - fwrite(mat->colind, sizeof(int32_t), mat->colptr[mat->ncols], fpout); - if (writevals) - fwrite(mat->colval, sizeof(float), mat->colptr[mat->ncols], fpout); - - gk_fclose(fpout); - return; - } - - if (filename) - fpout = gk_fopen(filename, "w", "gk_csr_Write: fpout"); - else - fpout = stdout; - - if (format == GK_CSR_FMT_CLUTO) { - fprintf(fpout, "%d %d %zd\n", mat->nrows, mat->ncols, mat->rowptr[mat->nrows]); - writevals = 1; - numbering = 1; - } - - for (i=0; i<mat->nrows; i++) { - for (j=mat->rowptr[i]; j<mat->rowptr[i+1]; j++) { - fprintf(fpout, " %d", mat->rowind[j]+(numbering ? 1 : 0)); - if (writevals) - fprintf(fpout, " %f", mat->rowval[j]); - } - fprintf(fpout, "\n"); - } - if (filename) - gk_fclose(fpout); -} - - -/*************************************************************************/ -/*! Prunes certain rows/columns of the matrix. The prunning takes place - by analyzing the row structure of the matrix. The prunning takes place - by removing rows/columns but it does not affect the numbering of the - remaining rows/columns. - - \param mat the matrix to be prunned, - \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) - of the matrix will be prunned, - \param minf is the minimum number of rows (columns) that a column (row) must - be present in order to be kept, - \param maxf is the maximum number of rows (columns) that a column (row) must - be present at in order to be kept. - \returns the prunned matrix consisting only of its row-based structure. - The input matrix is not modified. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_Prune(gk_csr_t *mat, int what, int minf, int maxf) -{ - ssize_t i, j, nnz; - int nrows, ncols; - ssize_t *rowptr, *nrowptr; - int *rowind, *nrowind, *collen; - float *rowval, *nrowval; - gk_csr_t *nmat; - - nmat = gk_csr_Create(); - - nrows = nmat->nrows = mat->nrows; - ncols = nmat->ncols = mat->ncols; - - rowptr = mat->rowptr; - rowind = mat->rowind; - rowval = mat->rowval; - - nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_Prune: nrowptr"); - nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_Prune: nrowind"); - nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_Prune: nrowval"); - - - switch (what) { - case GK_CSR_COL: - collen = gk_ismalloc(ncols, 0, "gk_csr_Prune: collen"); - - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - ASSERT(rowind[j] < ncols); - collen[rowind[j]]++; - } - } - for (i=0; i<ncols; i++) - collen[i] = (collen[i] >= minf && collen[i] <= maxf ? 1 : 0); - - nrowptr[0] = 0; - for (nnz=0, i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (collen[rowind[j]]) { - nrowind[nnz] = rowind[j]; - nrowval[nnz] = rowval[j]; - nnz++; - } - } - nrowptr[i+1] = nnz; - } - gk_free((void **)&collen, LTERM); - break; - - case GK_CSR_ROW: - nrowptr[0] = 0; - for (nnz=0, i=0; i<nrows; i++) { - if (rowptr[i+1]-rowptr[i] >= minf && rowptr[i+1]-rowptr[i] <= maxf) { - for (j=rowptr[i]; j<rowptr[i+1]; j++, nnz++) { - nrowind[nnz] = rowind[j]; - nrowval[nnz] = rowval[j]; - } - } - nrowptr[i+1] = nnz; - } - break; - - default: - gk_csr_Free(&nmat); - gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); - return NULL; - } - - return nmat; -} - - -/*************************************************************************/ -/*! Eliminates certain entries from the rows/columns of the matrix. The - filtering takes place by keeping only the highest weight entries whose - sum accounts for a certain fraction of the overall weight of the - row/column. - - \param mat the matrix to be prunned, - \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) - of the matrix will be prunned, - \param norm indicates the norm that will be used to aggregate the weights - and possible values are 1 or 2, - \param fraction is the fraction of the overall norm that will be retained - by the kept entries. - \returns the filtered matrix consisting only of its row-based structure. - The input matrix is not modified. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_LowFilter(gk_csr_t *mat, int what, int norm, float fraction) -{ - ssize_t i, j, nnz; - int nrows, ncols, ncand, maxlen=0; - ssize_t *rowptr, *colptr, *nrowptr; - int *rowind, *colind, *nrowind; - float *rowval, *colval, *nrowval, rsum, tsum; - gk_csr_t *nmat; - gk_fkv_t *cand; - - nmat = gk_csr_Create(); - - nrows = nmat->nrows = mat->nrows; - ncols = nmat->ncols = mat->ncols; - - rowptr = mat->rowptr; - rowind = mat->rowind; - rowval = mat->rowval; - colptr = mat->colptr; - colind = mat->colind; - colval = mat->colval; - - nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_LowFilter: nrowptr"); - nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_LowFilter: nrowind"); - nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_LowFilter: nrowval"); - - - switch (what) { - case GK_CSR_COL: - if (mat->colptr == NULL) - gk_errexit(SIGERR, "Cannot filter columns when column-based structure has not been created.\n"); - - gk_zcopy(nrows+1, rowptr, nrowptr); - - for (i=0; i<ncols; i++) - maxlen = gk_max(maxlen, colptr[i+1]-colptr[i]); - - #pragma omp parallel private(i, j, ncand, rsum, tsum, cand) - { - cand = gk_fkvmalloc(maxlen, "gk_csr_LowFilter: cand"); - - #pragma omp for schedule(static) - for (i=0; i<ncols; i++) { - for (tsum=0.0, ncand=0, j=colptr[i]; j<colptr[i+1]; j++, ncand++) { - cand[ncand].val = colind[j]; - cand[ncand].key = colval[j]; - tsum += (norm == 1 ? colval[j] : colval[j]*colval[j]); - } - gk_fkvsortd(ncand, cand); - - for (rsum=0.0, j=0; j<ncand && rsum<=fraction*tsum; j++) { - rsum += (norm == 1 ? cand[j].key : cand[j].key*cand[j].key); - nrowind[nrowptr[cand[j].val]] = i; - nrowval[nrowptr[cand[j].val]] = cand[j].key; - nrowptr[cand[j].val]++; - } - } - - gk_free((void **)&cand, LTERM); - } - - /* compact the nrowind/nrowval */ - for (nnz=0, i=0; i<nrows; i++) { - for (j=rowptr[i]; j<nrowptr[i]; j++, nnz++) { - nrowind[nnz] = nrowind[j]; - nrowval[nnz] = nrowval[j]; - } - nrowptr[i] = nnz; - } - SHIFTCSR(i, nrows, nrowptr); - - break; - - case GK_CSR_ROW: - if (mat->rowptr == NULL) - gk_errexit(SIGERR, "Cannot filter rows when row-based structure has not been created.\n"); - - for (i=0; i<nrows; i++) - maxlen = gk_max(maxlen, rowptr[i+1]-rowptr[i]); - - #pragma omp parallel private(i, j, ncand, rsum, tsum, cand) - { - cand = gk_fkvmalloc(maxlen, "gk_csr_LowFilter: cand"); - - #pragma omp for schedule(static) - for (i=0; i<nrows; i++) { - for (tsum=0.0, ncand=0, j=rowptr[i]; j<rowptr[i+1]; j++, ncand++) { - cand[ncand].val = rowind[j]; - cand[ncand].key = rowval[j]; - tsum += (norm == 1 ? rowval[j] : rowval[j]*rowval[j]); - } - gk_fkvsortd(ncand, cand); - - for (rsum=0.0, j=0; j<ncand && rsum<=fraction*tsum; j++) { - rsum += (norm == 1 ? cand[j].key : cand[j].key*cand[j].key); - nrowind[rowptr[i]+j] = cand[j].val; - nrowval[rowptr[i]+j] = cand[j].key; - } - nrowptr[i+1] = rowptr[i]+j; - } - - gk_free((void **)&cand, LTERM); - } - - /* compact nrowind/nrowval */ - nrowptr[0] = nnz = 0; - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<nrowptr[i+1]; j++, nnz++) { - nrowind[nnz] = nrowind[j]; - nrowval[nnz] = nrowval[j]; - } - nrowptr[i+1] = nnz; - } - - break; - - default: - gk_csr_Free(&nmat); - gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); - return NULL; - } - - return nmat; -} - - -/*************************************************************************/ -/*! Eliminates certain entries from the rows/columns of the matrix. The - filtering takes place by keeping only the highest weight top-K entries - along each row/column and those entries whose weight is greater than - a specified value. - - \param mat the matrix to be prunned, - \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) - of the matrix will be prunned, - \param topk is the number of the highest weight entries to keep. - \param keepval is the weight of a term above which will be kept. This - is used to select additional terms past the first topk. - \returns the filtered matrix consisting only of its row-based structure. - The input matrix is not modified. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_TopKPlusFilter(gk_csr_t *mat, int what, int topk, float keepval) -{ - ssize_t i, j, k, nnz; - int nrows, ncols, ncand; - ssize_t *rowptr, *colptr, *nrowptr; - int *rowind, *colind, *nrowind; - float *rowval, *colval, *nrowval; - gk_csr_t *nmat; - gk_fkv_t *cand; - - nmat = gk_csr_Create(); - - nrows = nmat->nrows = mat->nrows; - ncols = nmat->ncols = mat->ncols; - - rowptr = mat->rowptr; - rowind = mat->rowind; - rowval = mat->rowval; - colptr = mat->colptr; - colind = mat->colind; - colval = mat->colval; - - nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_LowFilter: nrowptr"); - nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_LowFilter: nrowind"); - nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_LowFilter: nrowval"); - - - switch (what) { - case GK_CSR_COL: - if (mat->colptr == NULL) - gk_errexit(SIGERR, "Cannot filter columns when column-based structure has not been created.\n"); - - cand = gk_fkvmalloc(nrows, "gk_csr_LowFilter: cand"); - - gk_zcopy(nrows+1, rowptr, nrowptr); - for (i=0; i<ncols; i++) { - for (ncand=0, j=colptr[i]; j<colptr[i+1]; j++, ncand++) { - cand[ncand].val = colind[j]; - cand[ncand].key = colval[j]; - } - gk_fkvsortd(ncand, cand); - - k = gk_min(topk, ncand); - for (j=0; j<k; j++) { - nrowind[nrowptr[cand[j].val]] = i; - nrowval[nrowptr[cand[j].val]] = cand[j].key; - nrowptr[cand[j].val]++; - } - for (; j<ncand; j++) { - if (cand[j].key < keepval) - break; - - nrowind[nrowptr[cand[j].val]] = i; - nrowval[nrowptr[cand[j].val]] = cand[j].key; - nrowptr[cand[j].val]++; - } - } - - /* compact the nrowind/nrowval */ - for (nnz=0, i=0; i<nrows; i++) { - for (j=rowptr[i]; j<nrowptr[i]; j++, nnz++) { - nrowind[nnz] = nrowind[j]; - nrowval[nnz] = nrowval[j]; - } - nrowptr[i] = nnz; - } - SHIFTCSR(i, nrows, nrowptr); - - gk_free((void **)&cand, LTERM); - break; - - case GK_CSR_ROW: - if (mat->rowptr == NULL) - gk_errexit(SIGERR, "Cannot filter rows when row-based structure has not been created.\n"); - - cand = gk_fkvmalloc(ncols, "gk_csr_LowFilter: cand"); - - nrowptr[0] = 0; - for (nnz=0, i=0; i<nrows; i++) { - for (ncand=0, j=rowptr[i]; j<rowptr[i+1]; j++, ncand++) { - cand[ncand].val = rowind[j]; - cand[ncand].key = rowval[j]; - } - gk_fkvsortd(ncand, cand); - - k = gk_min(topk, ncand); - for (j=0; j<k; j++, nnz++) { - nrowind[nnz] = cand[j].val; - nrowval[nnz] = cand[j].key; - } - for (; j<ncand; j++, nnz++) { - if (cand[j].key < keepval) - break; - - nrowind[nnz] = cand[j].val; - nrowval[nnz] = cand[j].key; - } - nrowptr[i+1] = nnz; - } - - gk_free((void **)&cand, LTERM); - break; - - default: - gk_csr_Free(&nmat); - gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); - return NULL; - } - - return nmat; -} - - -/*************************************************************************/ -/*! Eliminates certain entries from the rows/columns of the matrix. The - filtering takes place by keeping only the terms whose contribution to - the total length of the document is greater than a user-splied multiple - over the average. - - This routine assumes that the vectors are normalized to be unit length. - - \param mat the matrix to be prunned, - \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) - of the matrix will be prunned, - \param zscore is the multiplicative factor over the average contribution - to the length of the document. - \returns the filtered matrix consisting only of its row-based structure. - The input matrix is not modified. -*/ -/**************************************************************************/ -gk_csr_t *gk_csr_ZScoreFilter(gk_csr_t *mat, int what, float zscore) -{ - ssize_t i, j, nnz; - int nrows; - ssize_t *rowptr, *nrowptr; - int *rowind, *nrowind; - float *rowval, *nrowval, avgwgt; - gk_csr_t *nmat; - - nmat = gk_csr_Create(); - - nmat->nrows = mat->nrows; - nmat->ncols = mat->ncols; - - nrows = mat->nrows; - rowptr = mat->rowptr; - rowind = mat->rowind; - rowval = mat->rowval; - - nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_ZScoreFilter: nrowptr"); - nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_ZScoreFilter: nrowind"); - nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_ZScoreFilter: nrowval"); - - - switch (what) { - case GK_CSR_COL: - gk_errexit(SIGERR, "This has not been implemented yet.\n"); - break; - - case GK_CSR_ROW: - if (mat->rowptr == NULL) - gk_errexit(SIGERR, "Cannot filter rows when row-based structure has not been created.\n"); - - nrowptr[0] = 0; - for (nnz=0, i=0; i<nrows; i++) { - avgwgt = zscore/(rowptr[i+1]-rowptr[i]); - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (rowval[j] > avgwgt) { - nrowind[nnz] = rowind[j]; - nrowval[nnz] = rowval[j]; - nnz++; - } - } - nrowptr[i+1] = nnz; - } - break; - - default: - gk_csr_Free(&nmat); - gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); - return NULL; - } - - return nmat; -} - - -/*************************************************************************/ -/*! Compacts the column-space of the matrix by removing empty columns. - As a result of the compaction, the column numbers are renumbered. - The compaction operation is done in place and only affects the row-based - representation of the matrix. - The new columns are ordered in decreasing frequency. - - \param mat the matrix whose empty columns will be removed. -*/ -/**************************************************************************/ -void gk_csr_CompactColumns(gk_csr_t *mat) -{ - ssize_t i; - int nrows, ncols, nncols; - ssize_t *rowptr; - int *rowind, *colmap; - gk_ikv_t *clens; - - nrows = mat->nrows; - ncols = mat->ncols; - rowptr = mat->rowptr; - rowind = mat->rowind; - - colmap = gk_imalloc(ncols, "gk_csr_CompactColumns: colmap"); - - clens = gk_ikvmalloc(ncols, "gk_csr_CompactColumns: clens"); - for (i=0; i<ncols; i++) { - clens[i].key = 0; - clens[i].val = i; - } - - for (i=0; i<rowptr[nrows]; i++) - clens[rowind[i]].key++; - gk_ikvsortd(ncols, clens); - - for (nncols=0, i=0; i<ncols; i++) { - if (clens[i].key > 0) - colmap[clens[i].val] = nncols++; - else - break; - } - - for (i=0; i<rowptr[nrows]; i++) - rowind[i] = colmap[rowind[i]]; - - mat->ncols = nncols; - - gk_free((void **)&colmap, &clens, LTERM); -} - - -/*************************************************************************/ -/*! Sorts the indices in increasing order - \param mat the matrix itself, - \param what is either GK_CSR_ROW or GK_CSR_COL indicating which set of - indices to sort. -*/ -/**************************************************************************/ -void gk_csr_SortIndices(gk_csr_t *mat, int what) -{ - int n, nn=0; - ssize_t *ptr; - int *ind; - float *val; - - switch (what) { - case GK_CSR_ROW: - if (!mat->rowptr) - gk_errexit(SIGERR, "Row-based view of the matrix does not exists.\n"); - - n = mat->nrows; - ptr = mat->rowptr; - ind = mat->rowind; - val = mat->rowval; - break; - - case GK_CSR_COL: - if (!mat->colptr) - gk_errexit(SIGERR, "Column-based view of the matrix does not exists.\n"); - - n = mat->ncols; - ptr = mat->colptr; - ind = mat->colind; - val = mat->colval; - break; - - default: - gk_errexit(SIGERR, "Invalid index type of %d.\n", what); - return; - } - - #pragma omp parallel if (n > 100) - { - ssize_t i, j, k; - gk_ikv_t *cand; - float *tval; - - #pragma omp single - for (i=0; i<n; i++) - nn = gk_max(nn, ptr[i+1]-ptr[i]); - - cand = gk_ikvmalloc(nn, "gk_csr_SortIndices: cand"); - tval = gk_fmalloc(nn, "gk_csr_SortIndices: tval"); - - #pragma omp for schedule(static) - for (i=0; i<n; i++) { - for (k=0, j=ptr[i]; j<ptr[i+1]; j++) { - if (j > ptr[i] && ind[j] < ind[j-1]) - k = 1; /* an inversion */ - cand[j-ptr[i]].val = j-ptr[i]; - cand[j-ptr[i]].key = ind[j]; - tval[j-ptr[i]] = val[j]; - } - if (k) { - gk_ikvsorti(ptr[i+1]-ptr[i], cand); - for (j=ptr[i]; j<ptr[i+1]; j++) { - ind[j] = cand[j-ptr[i]].key; - val[j] = tval[cand[j-ptr[i]].val]; - } - } - } - - gk_free((void **)&cand, &tval, LTERM); - } - -} - - -/*************************************************************************/ -/*! Creates a row/column index from the column/row data. - \param mat the matrix itself, - \param what is either GK_CSR_ROW or GK_CSR_COL indicating which index - will be created. -*/ -/**************************************************************************/ -void gk_csr_CreateIndex(gk_csr_t *mat, int what) -{ - /* 'f' stands for forward, 'r' stands for reverse */ - ssize_t i, j, k, nf, nr; - ssize_t *fptr, *rptr; - int *find, *rind; - float *fval, *rval; - - switch (what) { - case GK_CSR_COL: - nf = mat->nrows; - fptr = mat->rowptr; - find = mat->rowind; - fval = mat->rowval; - - if (mat->colptr) gk_free((void **)&mat->colptr, LTERM); - if (mat->colind) gk_free((void **)&mat->colind, LTERM); - if (mat->colval) gk_free((void **)&mat->colval, LTERM); - - nr = mat->ncols; - rptr = mat->colptr = gk_zsmalloc(nr+1, 0, "gk_csr_CreateIndex: rptr"); - rind = mat->colind = gk_imalloc(fptr[nf], "gk_csr_CreateIndex: rind"); - rval = mat->colval = (fval ? gk_fmalloc(fptr[nf], "gk_csr_CreateIndex: rval") : NULL); - break; - case GK_CSR_ROW: - nf = mat->ncols; - fptr = mat->colptr; - find = mat->colind; - fval = mat->colval; - - if (mat->rowptr) gk_free((void **)&mat->rowptr, LTERM); - if (mat->rowind) gk_free((void **)&mat->rowind, LTERM); - if (mat->rowval) gk_free((void **)&mat->rowval, LTERM); - - nr = mat->nrows; - rptr = mat->rowptr = gk_zsmalloc(nr+1, 0, "gk_csr_CreateIndex: rptr"); - rind = mat->rowind = gk_imalloc(fptr[nf], "gk_csr_CreateIndex: rind"); - rval = mat->rowval = (fval ? gk_fmalloc(fptr[nf], "gk_csr_CreateIndex: rval") : NULL); - break; - default: - gk_errexit(SIGERR, "Invalid index type of %d.\n", what); - return; - } - - - for (i=0; i<nf; i++) { - for (j=fptr[i]; j<fptr[i+1]; j++) - rptr[find[j]]++; - } - MAKECSR(i, nr, rptr); - - if (rptr[nr] > 6*nr) { - for (i=0; i<nf; i++) { - for (j=fptr[i]; j<fptr[i+1]; j++) - rind[rptr[find[j]]++] = i; - } - SHIFTCSR(i, nr, rptr); - - if (fval) { - for (i=0; i<nf; i++) { - for (j=fptr[i]; j<fptr[i+1]; j++) - rval[rptr[find[j]]++] = fval[j]; - } - SHIFTCSR(i, nr, rptr); - } - } - else { - if (fval) { - for (i=0; i<nf; i++) { - for (j=fptr[i]; j<fptr[i+1]; j++) { - k = find[j]; - rind[rptr[k]] = i; - rval[rptr[k]++] = fval[j]; - } - } - } - else { - for (i=0; i<nf; i++) { - for (j=fptr[i]; j<fptr[i+1]; j++) - rind[rptr[find[j]]++] = i; - } - } - SHIFTCSR(i, nr, rptr); - } -} - - -/*************************************************************************/ -/*! Normalizes the rows/columns of the matrix to be unit - length. - \param mat the matrix itself, - \param what indicates what will be normalized and is obtained by - specifying GK_CSR_ROW, GK_CSR_COL, GK_CSR_ROW|GK_CSR_COL. - \param norm indicates what norm is to normalize to, 1: 1-norm, 2: 2-norm -*/ -/**************************************************************************/ -void gk_csr_Normalize(gk_csr_t *mat, int what, int norm) -{ - ssize_t i, j; - int n; - ssize_t *ptr; - float *val, sum; - - if (what&GK_CSR_ROW && mat->rowval) { - n = mat->nrows; - ptr = mat->rowptr; - val = mat->rowval; - - #pragma omp parallel if (ptr[n] > OMPMINOPS) - { - #pragma omp for private(j,sum) schedule(static) - for (i=0; i<n; i++) { - for (sum=0.0, j=ptr[i]; j<ptr[i+1]; j++){ - if (norm == 2) - sum += val[j]*val[j]; - else if (norm == 1) - sum += val[j]; /* assume val[j] > 0 */ - } - if (sum > 0) { - if (norm == 2) - sum=1.0/sqrt(sum); - else if (norm == 1) - sum=1.0/sum; - for (j=ptr[i]; j<ptr[i+1]; j++) - val[j] *= sum; - - } - } - } - } - - if (what&GK_CSR_COL && mat->colval) { - n = mat->ncols; - ptr = mat->colptr; - val = mat->colval; - - #pragma omp parallel if (ptr[n] > OMPMINOPS) - { - #pragma omp for private(j,sum) schedule(static) - for (i=0; i<n; i++) { - for (sum=0.0, j=ptr[i]; j<ptr[i+1]; j++) - if (norm == 2) - sum += val[j]*val[j]; - else if (norm == 1) - sum += val[j]; - if (sum > 0) { - if (norm == 2) - sum=1.0/sqrt(sum); - else if (norm == 1) - sum=1.0/sum; - for (j=ptr[i]; j<ptr[i+1]; j++) - val[j] *= sum; - } - } - } - } -} - - -/*************************************************************************/ -/*! Applies different row scaling methods. - \param mat the matrix itself, - \param type indicates the type of row scaling. Possible values are: - GK_CSR_MAXTF, GK_CSR_SQRT, GK_CSR_LOG, GK_CSR_IDF, GK_CSR_MAXTF2. -*/ -/**************************************************************************/ -void gk_csr_Scale(gk_csr_t *mat, int type) -{ - ssize_t i, j; - int nrows, ncols, nnzcols, bgfreq; - ssize_t *rowptr; - int *rowind, *collen; - float *rowval, *cscale, maxtf; - - nrows = mat->nrows; - rowptr = mat->rowptr; - rowind = mat->rowind; - rowval = mat->rowval; - - switch (type) { - case GK_CSR_MAXTF: /* TF' = .5 + .5*TF/MAX(TF) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j, maxtf) schedule(static) - for (i=0; i<nrows; i++) { - maxtf = fabs(rowval[rowptr[i]]); - for (j=rowptr[i]; j<rowptr[i+1]; j++) - maxtf = (maxtf < fabs(rowval[j]) ? fabs(rowval[j]) : maxtf); - - for (j=rowptr[i]; j<rowptr[i+1]; j++) - rowval[j] = .5 + .5*rowval[j]/maxtf; - } - } - break; - - case GK_CSR_MAXTF2: /* TF' = .1 + .9*TF/MAX(TF) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j, maxtf) schedule(static) - for (i=0; i<nrows; i++) { - maxtf = fabs(rowval[rowptr[i]]); - for (j=rowptr[i]; j<rowptr[i+1]; j++) - maxtf = (maxtf < fabs(rowval[j]) ? fabs(rowval[j]) : maxtf); - - for (j=rowptr[i]; j<rowptr[i+1]; j++) - rowval[j] = .1 + .9*rowval[j]/maxtf; - } - } - break; - - case GK_CSR_SQRT: /* TF' = .1+SQRT(TF) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (rowval[j] != 0.0) - rowval[j] = .1+sign(rowval[j], sqrt(fabs(rowval[j]))); - } - } - } - break; - - case GK_CSR_POW25: /* TF' = .1+POW(TF,.25) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (rowval[j] != 0.0) - rowval[j] = .1+sign(rowval[j], sqrt(sqrt(fabs(rowval[j])))); - } - } - } - break; - - case GK_CSR_POW65: /* TF' = .1+POW(TF,.65) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (rowval[j] != 0.0) - rowval[j] = .1+sign(rowval[j], powf(fabs(rowval[j]), .65)); - } - } - } - break; - - case GK_CSR_POW75: /* TF' = .1+POW(TF,.75) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (rowval[j] != 0.0) - rowval[j] = .1+sign(rowval[j], powf(fabs(rowval[j]), .75)); - } - } - } - break; - - case GK_CSR_POW85: /* TF' = .1+POW(TF,.85) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (rowval[j] != 0.0) - rowval[j] = .1+sign(rowval[j], powf(fabs(rowval[j]), .85)); - } - } - } - break; - - case GK_CSR_LOG: /* TF' = 1+log_2(TF) */ - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - double logscale = 1.0/log(2.0); - #pragma omp for schedule(static,32) - for (i=0; i<rowptr[nrows]; i++) { - if (rowval[i] != 0.0) - rowval[i] = 1+(rowval[i]>0.0 ? log(rowval[i]) : -log(-rowval[i]))*logscale; - } -#ifdef XXX - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) { - if (rowval[j] != 0.0) - rowval[j] = 1+(rowval[j]>0.0 ? log(rowval[j]) : -log(-rowval[j]))*logscale; - //rowval[j] = 1+sign(rowval[j], log(fabs(rowval[j]))*logscale); - } - } -#endif - } - break; - - case GK_CSR_IDF: /* TF' = TF*IDF */ - ncols = mat->ncols; - cscale = gk_fmalloc(ncols, "gk_csr_Scale: cscale"); - collen = gk_ismalloc(ncols, 0, "gk_csr_Scale: collen"); - - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) - collen[rowind[j]]++; - } - - #pragma omp parallel if (ncols > OMPMINOPS) - { - #pragma omp for schedule(static) - for (i=0; i<ncols; i++) - cscale[i] = (collen[i] > 0 ? log(1.0*nrows/collen[i]) : 0.0); - } - - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) - rowval[j] *= cscale[rowind[j]]; - } - } - - gk_free((void **)&cscale, &collen, LTERM); - break; - - case GK_CSR_IDF2: /* TF' = TF*IDF */ - ncols = mat->ncols; - cscale = gk_fmalloc(ncols, "gk_csr_Scale: cscale"); - collen = gk_ismalloc(ncols, 0, "gk_csr_Scale: collen"); - - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) - collen[rowind[j]]++; - } - - nnzcols = 0; - #pragma omp parallel if (ncols > OMPMINOPS) - { - #pragma omp for schedule(static) reduction(+:nnzcols) - for (i=0; i<ncols; i++) - nnzcols += (collen[i] > 0 ? 1 : 0); - - bgfreq = gk_max(10, (ssize_t)(.5*rowptr[nrows]/nnzcols)); - printf("nnz: %zd, nnzcols: %d, bgfreq: %d\n", rowptr[nrows], nnzcols, bgfreq); - - #pragma omp for schedule(static) - for (i=0; i<ncols; i++) - cscale[i] = (collen[i] > 0 ? log(1.0*(nrows+2*bgfreq)/(bgfreq+collen[i])) : 0.0); - } - - #pragma omp parallel if (rowptr[nrows] > OMPMINOPS) - { - #pragma omp for private(j) schedule(static) - for (i=0; i<nrows; i++) { - for (j=rowptr[i]; j<rowptr[i+1]; j++) - rowval[j] *= cscale[rowind[j]]; - } - } - - gk_free((void **)&cscale, &collen, LTERM); - break; - - default: - gk_errexit(SIGERR, "Unknown scaling type of %d\n", type); - } - -} - - -/*************************************************************************/ -/*! Computes the sums of the rows/columns - \param mat the matrix itself, - \param what is either GK_CSR_ROW or GK_CSR_COL indicating which - sums to compute. -*/ -/**************************************************************************/ -void gk_csr_ComputeSums(gk_csr_t *mat, int what) -{ - ssize_t i; - int n; - ssize_t *ptr; - float *val, *sums; - - switch (what) { - case GK_CSR_ROW: - n = mat->nrows; - ptr = mat->rowptr; - val = mat->rowval; - - if (mat->rsums) - gk_free((void **)&mat->rsums, LTERM); - - sums = mat->rsums = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: sums"); - break; - case GK_CSR_COL: - n = mat->ncols; - ptr = mat->colptr; - val = mat->colval; - - if (mat->csums) - gk_free((void **)&mat->csums, LTERM); - - sums = mat->csums = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: sums"); - break; - default: - gk_errexit(SIGERR, "Invalid sum type of %d.\n", what); - return; - } - - #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) - for (i=0; i<n; i++) - sums[i] = gk_fsum(ptr[i+1]-ptr[i], val+ptr[i], 1); -} - - -/*************************************************************************/ -/*! Computes the squared of the norms of the rows/columns - \param mat the matrix itself, - \param what is either GK_CSR_ROW or GK_CSR_COL indicating which - squared norms to compute. -*/ -/**************************************************************************/ -void gk_csr_ComputeSquaredNorms(gk_csr_t *mat, int what) -{ - ssize_t i; - int n; - ssize_t *ptr; - float *val, *norms; - - switch (what) { - case GK_CSR_ROW: - n = mat->nrows; - ptr = mat->rowptr; - val = mat->rowval; - - if (mat->rnorms) gk_free((void **)&mat->rnorms, LTERM); - - norms = mat->rnorms = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: norms"); - break; - case GK_CSR_COL: - n = mat->ncols; - ptr = mat->colptr; - val = mat->colval; - - if (mat->cnorms) gk_free((void **)&mat->cnorms, LTERM); - - norms = mat->cnorms = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: norms"); - break; - default: - gk_errexit(SIGERR, "Invalid norm type of %d.\n", what); - return; - } - - #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) - for (i=0; i<n; i++) - norms[i] = gk_fdot(ptr[i+1]-ptr[i], val+ptr[i], 1, val+ptr[i], 1); -} - - -/*************************************************************************/ -/*! Computes the similarity between two rows/columns - - \param mat the matrix itself. The routine assumes that the indices - are sorted in increasing order. - \param i1 is the first row/column, - \param i2 is the second row/column, - \param what is either GK_CSR_ROW or GK_CSR_COL indicating the type of - objects between the similarity will be computed, - \param simtype is the type of similarity and is one of GK_CSR_COS, - GK_CSR_JAC, GK_CSR_MIN, GK_CSR_AMIN - \returns the similarity between the two rows/columns. -*/ -/**************************************************************************/ -float gk_csr_ComputeSimilarity(gk_csr_t *mat, int i1, int i2, int what, int simtype) -{ - int nind1, nind2; - int *ind1, *ind2; - float *val1, *val2, stat1, stat2, sim; - - switch (what) { - case GK_CSR_ROW: - if (!mat->rowptr) - gk_errexit(SIGERR, "Row-based view of the matrix does not exists.\n"); - nind1 = mat->rowptr[i1+1]-mat->rowptr[i1]; - nind2 = mat->rowptr[i2+1]-mat->rowptr[i2]; - ind1 = mat->rowind + mat->rowptr[i1]; - ind2 = mat->rowind + mat->rowptr[i2]; - val1 = mat->rowval + mat->rowptr[i1]; - val2 = mat->rowval + mat->rowptr[i2]; - break; - - case GK_CSR_COL: - if (!mat->colptr) - gk_errexit(SIGERR, "Column-based view of the matrix does not exists.\n"); - nind1 = mat->colptr[i1+1]-mat->colptr[i1]; - nind2 = mat->colptr[i2+1]-mat->colptr[i2]; - ind1 = mat->colind + mat->colptr[i1]; - ind2 = mat->colind + mat->colptr[i2]; - val1 = mat->colval + mat->colptr[i1]; - val2 = mat->colval + mat->colptr[i2]; - break; - - default: - gk_errexit(SIGERR, "Invalid index type of %d.\n", what); - return 0.0; - } - - - switch (simtype) { - case GK_CSR_COS: - case GK_CSR_JAC: - sim = stat1 = stat2 = 0.0; - i1 = i2 = 0; - while (i1<nind1 && i2<nind2) { - if (i1 == nind1) { - stat2 += val2[i2]*val2[i2]; - i2++; - } - else if (i2 == nind2) { - stat1 += val1[i1]*val1[i1]; - i1++; - } - else if (ind1[i1] < ind2[i2]) { - stat1 += val1[i1]*val1[i1]; - i1++; - } - else if (ind1[i1] > ind2[i2]) { - stat2 += val2[i2]*val2[i2]; - i2++; - } - else { - sim += val1[i1]*val2[i2]; - stat1 += val1[i1]*val1[i1]; - stat2 += val2[i2]*val2[i2]; - i1++; - i2++; - } - } - if (simtype == GK_CSR_COS) - sim = (stat1*stat2 > 0.0 ? sim/sqrt(stat1*stat2) : 0.0); - else - sim = (stat1+stat2-sim > 0.0 ? sim/(stat1+stat2-sim) : 0.0); - break; - - case GK_CSR_MIN: - sim = stat1 = stat2 = 0.0; - i1 = i2 = 0; - while (i1<nind1 && i2<nind2) { - if (i1 == nind1) { - stat2 += val2[i2]; - i2++; - } - else if (i2 == nind2) { - stat1 += val1[i1]; - i1++; - } - else if (ind1[i1] < ind2[i2]) { - stat1 += val1[i1]; - i1++; - } - else if (ind1[i1] > ind2[i2]) { - stat2 += val2[i2]; - i2++; - } - else { - sim += gk_min(val1[i1],val2[i2]); - stat1 += val1[i1]; - stat2 += val2[i2]; - i1++; - i2++; - } - } - sim = (stat1+stat2-sim > 0.0 ? sim/(stat1+stat2-sim) : 0.0); - - break; - - case GK_CSR_AMIN: - sim = stat1 = stat2 = 0.0; - i1 = i2 = 0; - while (i1<nind1 && i2<nind2) { - if (i1 == nind1) { - stat2 += val2[i2]; - i2++; - } - else if (i2 == nind2) { - stat1 += val1[i1]; - i1++; - } - else if (ind1[i1] < ind2[i2]) { - stat1 += val1[i1]; - i1++; - } - else if (ind1[i1] > ind2[i2]) { - stat2 += val2[i2]; - i2++; - } - else { - sim += gk_min(val1[i1],val2[i2]); - stat1 += val1[i1]; - stat2 += val2[i2]; - i1++; - i2++; - } - } - sim = (stat1 > 0.0 ? sim/stat1 : 0.0); - - break; - - default: - gk_errexit(SIGERR, "Unknown similarity measure %d\n", simtype); - return -1; - } - - return sim; - -} - - -/*************************************************************************/ -/*! Finds the n most similar rows (neighbors) to the query using cosine - similarity. - - \param mat the matrix itself - \param nqterms is the number of columns in the query - \param qind is the list of query columns - \param qval is the list of correspodning query weights - \param simtype is the type of similarity and is one of GK_CSR_COS, - GK_CSR_JAC, GK_CSR_MIN, GK_CSR_AMIN - \param nsim is the maximum number of requested most similar rows. - If -1 is provided, then everything is returned unsorted. - \param minsim is the minimum similarity of the requested most - similar rows - \param hits is the result set. This array should be at least - of length nsim. - \param i_marker is an array of size equal to the number of rows - whose values are initialized to -1. If NULL is provided - then this array is allocated and freed internally. - \param i_cand is an array of size equal to the number of rows. - If NULL is provided then this array is allocated and freed - internally. - \returns the number of identified most similar rows, which can be - smaller than the requested number of nnbrs in those cases - in which there are no sufficiently many neighbors. -*/ -/**************************************************************************/ -int gk_csr_GetSimilarRows(gk_csr_t *mat, int nqterms, int *qind, - float *qval, int simtype, int nsim, float minsim, gk_fkv_t *hits, - int *i_marker, gk_fkv_t *i_cand) -{ - ssize_t i, ii, j, k; - int nrows, ncols, ncand; - ssize_t *colptr; - int *colind, *marker; - float *colval, *rnorms, mynorm, *rsums, mysum; - gk_fkv_t *cand; - - if (nqterms == 0) - return 0; - - nrows = mat->nrows; - ncols = mat->ncols; - colptr = mat->colptr; - colind = mat->colind; - colval = mat->colval; - - marker = (i_marker ? i_marker : gk_ismalloc(nrows, -1, "gk_csr_SimilarRows: marker")); - cand = (i_cand ? i_cand : gk_fkvmalloc(nrows, "gk_csr_SimilarRows: cand")); - - switch (simtype) { - case GK_CSR_COS: - for (ncand=0, ii=0; ii<nqterms; ii++) { - i = qind[ii]; - if (i < ncols) { - for (j=colptr[i]; j<colptr[i+1]; j++) { - k = colind[j]; - if (marker[k] == -1) { - cand[ncand].val = k; - cand[ncand].key = 0; - marker[k] = ncand++; - } - cand[marker[k]].key += colval[j]*qval[ii]; - } - } - } - break; - - case GK_CSR_JAC: - for (ncand=0, ii=0; ii<nqterms; ii++) { - i = qind[ii]; - if (i < ncols) { - for (j=colptr[i]; j<colptr[i+1]; j++) { - k = colind[j]; - if (marker[k] == -1) { - cand[ncand].val = k; - cand[ncand].key = 0; - marker[k] = ncand++; - } - cand[marker[k]].key += colval[j]*qval[ii]; - } - } - } - - rnorms = mat->rnorms; - mynorm = gk_fdot(nqterms, qval, 1, qval, 1); - - for (i=0; i<ncand; i++) - cand[i].key = cand[i].key/(rnorms[cand[i].val]+mynorm-cand[i].key); - break; - - case GK_CSR_MIN: - for (ncand=0, ii=0; ii<nqterms; ii++) { - i = qind[ii]; - if (i < ncols) { - for (j=colptr[i]; j<colptr[i+1]; j++) { - k = colind[j]; - if (marker[k] == -1) { - cand[ncand].val = k; - cand[ncand].key = 0; - marker[k] = ncand++; - } - cand[marker[k]].key += gk_min(colval[j], qval[ii]); - } - } - } - - rsums = mat->rsums; - mysum = gk_fsum(nqterms, qval, 1); - - for (i=0; i<ncand; i++) - cand[i].key = cand[i].key/(rsums[cand[i].val]+mysum-cand[i].key); - break; - - /* Assymetric MIN similarity */ - case GK_CSR_AMIN: - for (ncand=0, ii=0; ii<nqterms; ii++) { - i = qind[ii]; - if (i < ncols) { - for (j=colptr[i]; j<colptr[i+1]; j++) { - k = colind[j]; - if (marker[k] == -1) { - cand[ncand].val = k; - cand[ncand].key = 0; - marker[k] = ncand++; - } - cand[marker[k]].key += gk_min(colval[j], qval[ii]); - } - } - } - - mysum = gk_fsum(nqterms, qval, 1); - - for (i=0; i<ncand; i++) - cand[i].key = cand[i].key/mysum; - break; - - default: - gk_errexit(SIGERR, "Unknown similarity measure %d\n", simtype); - return -1; - } - - /* go and prune the hits that are bellow minsim */ - for (j=0, i=0; i<ncand; i++) { - marker[cand[i].val] = -1; - if (cand[i].key >= minsim) - cand[j++] = cand[i]; - } - ncand = j; - - if (nsim == -1 || nsim >= ncand) { - nsim = ncand; - } - else { - nsim = gk_min(nsim, ncand); - gk_dfkvkselect(ncand, nsim, cand); - gk_fkvsortd(nsim, cand); - } - - gk_fkvcopy(nsim, cand, hits); - - if (i_marker == NULL) - gk_free((void **)&marker, LTERM); - if (i_cand == NULL) - gk_free((void **)&cand, LTERM); - - return nsim; -} - diff --git a/3rdParty/metis/metis-5.1.0/GKlib/omp.c b/3rdParty/metis/metis-5.1.0/GKlib/omp.c deleted file mode 100644 index bdd543acf40099863bb99675892d0b14fda8e653..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/omp.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 1997, Regents of the University of Minnesota - * - * omp.c - * - * This file contains "fake" implementations of OpenMP's runtime libraries - * - */ - -#include <GKlib.h> - -#ifdef GK_NOOPENMP /* remove those for now */ -#if !defined(_OPENMP) -void omp_set_num_threads(int num_threads) { return; } -int omp_get_num_threads(void) { return 1; } -int omp_get_max_threads(void) { return 1; } -int omp_get_thread_num(void) { return 0; } -int omp_get_num_procs(void) { return 1; } -int omp_in_parallel(void) { return 0; } -void omp_set_dynamic(int num_threads) { return; } -int omp_get_dynamic(void) { return 0; } -void omp_set_nested(int nested) { return; } -int omp_get_nested(void) { return 0; } -#endif -#endif - - diff --git a/3rdParty/metis/metis-5.1.0/GKlib/pdb.c b/3rdParty/metis/metis-5.1.0/GKlib/pdb.c deleted file mode 100644 index b4d222653e7133570aeddaa492f7e6e5381640fe..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/pdb.c +++ /dev/null @@ -1,460 +0,0 @@ -/************************************************************************/ -/*! \file pdb.c - -\brief Functions for parsing pdb files. - -Pdb reader (parser). Loads arrays of pointers for easy backbone access. - -\date Started 10/20/06 -\author Kevin -\version $Id: pdb.c 10711 2011-08-31 22:23:04Z karypis $ -*/ -/************************************************************************/ -#include <GKlib.h> - -/************************************************************************/ -/*! \brief Converts three-letter amino acid codes to one-leter codes. - -This function takes a three letter \c * and converts it to a single \c - -\param res is the three-letter code to be converted. -\returns A \c representing the amino acid. -*/ -/************************************************************************/ -char gk_threetoone(char *res) { /* {{{ */ - /* make sure the matching works */ - res[0] = toupper(res[0]); - res[1] = toupper(res[1]); - res[2] = toupper(res[2]); - if(strcmp(res,"ALA") == 0) { - return 'A'; - } - else if(strcmp(res,"CYS") == 0) { - return 'C'; - } - else if(strcmp(res,"ASP") == 0) { - return 'D'; - } - else if(strcmp(res,"GLU") == 0) { - return 'E'; - } - else if(strcmp(res,"PHE") == 0) { - return 'F'; - } - else if(strcmp(res,"GLY") == 0) { - return 'G'; - } - else if(strcmp(res,"HIS") == 0) { - return 'H'; - } - else if(strcmp(res,"ILE") == 0) { - return 'I'; - } - else if(strcmp(res,"LYS") == 0) { - return 'K'; - } - else if(strcmp(res,"LEU") == 0) { - return 'L'; - } - else if(strcmp(res,"MET") == 0) { - return 'M'; - } - else if(strcmp(res,"ASN") == 0) { - return 'N'; - } - else if(strcmp(res,"PRO") == 0) { - return 'P'; - } - else if(strcmp(res,"GLN") == 0) { - return 'Q'; - } - else if(strcmp(res,"ARG") == 0) { - return 'R'; - } - else if(strcmp(res,"SER") == 0) { - return 'S'; - } - else if(strcmp(res,"THR") == 0) { - return 'T'; - } - else if(strcmp(res,"SCY") == 0) { - return 'U'; - } - else if(strcmp(res,"VAL") == 0) { - return 'V'; - } - else if(strcmp(res,"TRP") == 0) { - return 'W'; - } - else if(strcmp(res,"TYR") == 0) { - return 'Y'; - } - else { - return 'X'; - } -} /* }}} */ - -/************************************************************************/ -/*! \brief Frees the memory of a pdbf structure. - -This function takes a pdbf pointer and frees all the memory below it. - -\param p is the pdbf structure to be freed. -*/ -/************************************************************************/ -void gk_freepdbf(pdbf *p) { /* {{{ */ - int i; - if(p != NULL) { - gk_free((void **)&p->resSeq, LTERM); - for(i=0; i<p->natoms; i++) { - gk_free((void **)&p->atoms[i].name, &p->atoms[i].resname, LTERM); - } - for(i=0; i<p->nresidues; i++) { - gk_free((void *)&p->threeresSeq[i], LTERM); - } - /* this may look like it's wrong, but it's just a 1-d array of pointers, and - the pointers themselves are freed above */ - gk_free((void **)&p->bbs, &p->cas, &p->atoms, &p->cm, &p->threeresSeq, LTERM); - } - gk_free((void **)&p, LTERM); -} /* }}} */ - -/************************************************************************/ -/*! \brief Reads a pdb file into a pdbf structure - -This function allocates a pdbf structure and reads the file fname into -that structure. - -\param fname is the file name to be read -\returns A filled pdbf structure. -*/ -/************************************************************************/ -pdbf *gk_readpdbfile(char *fname) { /* {{{ */ - int i=0, res=0; - char linetype[6]; - int aserial; - char aname[5] = " \0"; - char altLoc = ' '; - char rname[4] = " \0"; - char chainid = ' '; - char oldchainid = ' '; - int rserial; - int oldRserial = -37; - char icode = ' '; - char element = ' '; - double x; - double y; - double z; - double avgx; - double avgy; - double avgz; - double opcy; - double tmpt; - char line[MAXLINELEN]; - int corruption=0; - int nresatoms; - - int atoms=0, residues=0, cas=0, bbs=0, firstres=1; - pdbf *toFill = gk_malloc(sizeof(pdbf),"fillme"); - FILE *FPIN; - - FPIN = gk_fopen(fname,"r",fname); - while(fgets(line, 256, FPIN)) { - sscanf(line,"%s ",linetype); - /* It seems the only reliable parts are through temperature, so we only use these parts */ - /* if(strstr(linetype, "ATOM") != NULL || strstr(linetype, "HETATM") != NULL) { */ - if(strstr(linetype, "ATOM") != NULL) { - sscanf(line, "%6s%5d%*1c%4c%1c%3c%*1c%1c%4d%1c%*3c%8lf%8lf%8lf%6lf%6lf %c\n", - linetype,&aserial,aname,&altLoc,rname,&chainid,&rserial,&icode,&x,&y,&z,&opcy,&tmpt,&element); - sscanf(linetype, " %s ",linetype); - sscanf(aname, " %s ",aname); - sscanf(rname, " %s ",rname); - if(altLoc != ' ') { - corruption = corruption|CRP_ALTLOCS; - } - - if(firstres == 1) { - oldRserial = rserial; - oldchainid = chainid; - residues++; - firstres = 0; - } - if(oldRserial != rserial) { - residues++; - oldRserial = rserial; - } - if(oldchainid != chainid) { - corruption = corruption|CRP_MULTICHAIN; - } - oldchainid = chainid; - atoms++; - if(strcmp(aname,"CA") == 0) { - cas++; - } - if(strcmp(aname,"N") == 0 || strcmp(aname,"CA") == 0 || - strcmp(aname,"C") == 0 || strcmp(aname,"O") == 0) { - bbs++; - } - } - else if(strstr(linetype, "ENDMDL") != NULL || strstr(linetype, "END") != NULL || strstr(linetype, "TER") != NULL) { - break; - } - } - fclose(FPIN); - - /* printf("File has coordinates for %d atoms in %d residues\n",atoms,residues); */ - toFill->natoms = atoms; - toFill->ncas = cas; - toFill->nbbs = bbs; - toFill->nresidues = residues; - toFill->resSeq = (char *) gk_malloc (residues*sizeof(char),"residue seq"); - toFill->threeresSeq = (char **)gk_malloc (residues*sizeof(char *),"residue seq"); - toFill->atoms = (atom *) gk_malloc (atoms*sizeof(atom), "atoms"); - toFill->bbs = (atom **)gk_malloc ( bbs*sizeof(atom *),"bbs"); - toFill->cas = (atom **)gk_malloc ( cas*sizeof(atom *),"cas"); - toFill->cm = (center_of_mass *)gk_malloc(residues*sizeof(center_of_mass),"center of mass"); - res=0; firstres=1; cas=0; bbs=0; i=0; - avgx = 0.0; avgy = 0.0; avgz = 0.0; - nresatoms = 0; - - FPIN = gk_fopen(fname,"r",fname); - while(fgets(line, 256, FPIN)) { - sscanf(line,"%s ",linetype); - /* It seems the only reliable parts are through temperature, so we only use these parts */ - /* if(strstr(linetype, "ATOM") != NULL || strstr(linetype, "HETATM") != NULL) { */ - if(strstr(linetype, "ATOM") != NULL ) { - - /* to ensure our memory doesn't get corrupted by the biologists, we only read this far */ - sscanf(line, "%6s%5d%*1c%4c%1c%3c%*1c%1c%4d%1c%*3c%8lf%8lf%8lf%6lf%6lf %c\n", - linetype,&aserial,aname,&altLoc,rname,&chainid,&rserial,&icode,&x,&y,&z,&opcy,&tmpt,&element); - sscanf(aname, "%s",aname); - sscanf(rname, "%s",rname); - - if(firstres == 1) { - toFill->resSeq[res] = gk_threetoone(rname); - toFill->threeresSeq[res] = gk_strdup(rname); - oldRserial = rserial; - res++; - firstres = 0; - } - if(oldRserial != rserial) { - /* we're changing residues. store the center of mass from the last one & reset */ - toFill->cm[res-1].x = avgx/nresatoms; - toFill->cm[res-1].y = avgy/nresatoms; - toFill->cm[res-1].z = avgz/nresatoms; - avgx = 0.0; avgy = 0.0; avgz = 0.0; - nresatoms = 0; - toFill->cm[res-1].name = toFill->resSeq[res-1]; - - toFill->threeresSeq[res] = gk_strdup(rname); - toFill->resSeq[res] = gk_threetoone(rname); - res++; - oldRserial = rserial; - } - avgx += x; - avgy += y; - avgz += z; - nresatoms++; - - toFill->atoms[i].x = x; - toFill->atoms[i].y = y; - toFill->atoms[i].z = z; - toFill->atoms[i].opcy = opcy; - toFill->atoms[i].tmpt = tmpt; - toFill->atoms[i].element = element; - toFill->atoms[i].serial = aserial; - toFill->atoms[i].chainid = chainid; - toFill->atoms[i].altLoc = altLoc; - toFill->atoms[i].rserial = rserial; - toFill->atoms[i].icode = icode; - toFill->atoms[i].name = gk_strdup(aname); - toFill->atoms[i].resname = gk_strdup(rname); - /* Set up pointers for the backbone and c-alpha shortcuts */ - if(strcmp(aname,"CA") == 0) { - toFill->cas[cas] = &(toFill->atoms[i]); - cas++; - } - if(strcmp(aname,"N") == 0 || strcmp(aname,"CA") == 0 || strcmp(aname,"C") == 0 || strcmp(aname,"O") == 0) { - toFill->bbs[bbs] = &(toFill->atoms[i]); - bbs++; - } - i++; - } - else if(strstr(linetype, "ENDMDL") != NULL || strstr(linetype, "END") != NULL || strstr(linetype, "TER") != NULL) { - break; - } - } - /* get that last average */ - toFill->cm[res-1].x = avgx/nresatoms; - toFill->cm[res-1].y = avgy/nresatoms; - toFill->cm[res-1].z = avgz/nresatoms; - /* Begin test code */ - if(cas != residues) { - printf("Number of residues and CA coordinates differs by %d (!)\n",residues-cas); - if(cas < residues) { - corruption = corruption|CRP_MISSINGCA; - } - else if(cas > residues) { - corruption = corruption|CRP_MULTICA; - } - } - if(bbs < residues*4) { - corruption = corruption|CRP_MISSINGBB; - } - else if(bbs > residues*4) { - corruption = corruption|CRP_MULTIBB; - } - fclose(FPIN); - toFill->corruption = corruption; - /* if(corruption == 0) - printf("File was clean!\n"); */ - return(toFill); -} /* }}} */ - -/************************************************************************/ -/*! \brief Writes the sequence of residues from a pdb file. - -This function takes a pdbf structure and a filename, and writes out -the amino acid sequence according to the atomic coordinates. The output -is in fasta format. - - -\param p is the pdbf structure with the sequence of interest -\param fname is the file name to be written -*/ -/************************************************************************/ -void gk_writefastafrompdb(pdbf *pb, char *fname) { - int i; - FILE *FPOUT; - - FPOUT = gk_fopen(fname,"w",fname); - fprintf(FPOUT,"> %s\n",fname); - - for(i=0; i<pb->nresidues; i++) - fprintf(FPOUT,"%c",pb->resSeq[i]); - - fprintf(FPOUT,"\n"); - fclose(FPOUT); -} - -/************************************************************************/ -/*! \brief Writes all centers of mass in pdb-format to file fname. - -This function takes a pdbf structure and writes out the calculated -mass center information to file fname as though each one was a c-alpha. - -\param p is the pdbf structure to write out -\param fname is the file name to be written -*/ -/************************************************************************/ -void gk_writecentersofmass(pdbf *p, char *fname) { - int i; - FILE *FPIN; - FPIN = gk_fopen(fname,"w",fname); - for(i=0; i<p->nresidues; i++) { - fprintf(FPIN,"%-6s%5d %4s%1c%3s %1c%4d%1c %8.3lf%8.3lf%8.3lf%6.2f%6.2f\n", - "ATOM ",i,"CA",' ',p->threeresSeq[i],' ',i,' ',p->cm[i].x,p->cm[i].y,p->cm[i].z,1.0,-37.0); - } - fclose(FPIN); -} - -/************************************************************************/ -/*! \brief Writes all atoms in p in pdb-format to file fname. - -This function takes a pdbf structure and writes out all the atom -information to file fname. - -\param p is the pdbf structure to write out -\param fname is the file name to be written -*/ -/************************************************************************/ -void gk_writefullatom(pdbf *p, char *fname) { - int i; - FILE *FPIN; - FPIN = gk_fopen(fname,"w",fname); - for(i=0; i<p->natoms; i++) { - fprintf(FPIN,"%-6s%5d %4s%1c%3s %1c%4d%1c %8.3lf%8.3lf%8.3lf%6.2f%6.2f\n", - "ATOM ",p->atoms[i].serial,p->atoms[i].name,p->atoms[i].altLoc,p->atoms[i].resname,p->atoms[i].chainid,p->atoms[i].rserial,p->atoms[i].icode,p->atoms[i].x,p->atoms[i].y,p->atoms[i].z,p->atoms[i].opcy,p->atoms[i].tmpt); - } - fclose(FPIN); -} - -/************************************************************************/ -/*! \brief Writes out all the backbone atoms of a structure in pdb format - -This function takes a pdbf structure p and writes only the backbone atoms -to a filename fname. - -\param p is the pdb structure to write out. -\param fname is the file name to be written. -*/ -/************************************************************************/ -void gk_writebackbone(pdbf *p, char *fname) { - int i; - FILE *FPIN; - FPIN = gk_fopen(fname,"w",fname); - for(i=0; i<p->nbbs; i++) { - fprintf(FPIN,"%-6s%5d %4s%1c%3s %1c%4d%1c %8.3lf%8.3lf%8.3lf%6.2f%6.2f\n", - "ATOM ",p->bbs[i]->serial,p->bbs[i]->name,p->bbs[i]->altLoc,p->bbs[i]->resname,p->bbs[i]->chainid,p->bbs[i]->rserial,p->bbs[i]->icode,p->bbs[i]->x,p->bbs[i]->y,p->bbs[i]->z,p->bbs[i]->opcy,p->bbs[i]->tmpt); - } - fclose(FPIN); -} - -/************************************************************************/ -/*! \brief Writes out all the alpha carbon atoms of a structure - -This function takes a pdbf structure p and writes only the alpha carbon -atoms to a filename fname. - -\param p is the pdb structure to write out. -\param fname is the file name to be written. -*/ -/************************************************************************/ -void gk_writealphacarbons(pdbf *p, char *fname) { - int i; - FILE *FPIN; - FPIN = gk_fopen(fname,"w",fname); - for(i=0; i<p->ncas; i++) { - fprintf(FPIN,"%-6s%5d %4s%1c%3s %1c%4d%1c %8.3lf%8.3lf%8.3lf%6.2f%6.2f\n", - "ATOM ",p->cas[i]->serial,p->cas[i]->name,p->cas[i]->altLoc,p->cas[i]->resname,p->cas[i]->chainid,p->cas[i]->rserial,p->cas[i]->icode,p->cas[i]->x,p->cas[i]->y,p->cas[i]->z,p->cas[i]->opcy,p->cas[i]->tmpt); - } - fclose(FPIN); -} - -/************************************************************************/ -/*! \brief Decodes the corruption bitswitch and prints any problems - -Due to the totally unreliable nature of the pdb format, reading a pdb -file stores a corruption bitswitch, and this function decodes that switch -and prints the result on stdout. - -\param p is the pdb structure to write out. -\param fname is the file name to be written. -*/ -/************************************************************************/ -void gk_showcorruption(pdbf *p) { - int corruption = p->corruption; - if(corruption&CRP_ALTLOCS) - printf("Multiple coordinate sets for at least one atom\n"); - if(corruption&CRP_MISSINGCA) - printf("Missing coordiantes for at least one CA atom\n"); - if(corruption&CRP_MISSINGBB) - printf("Missing coordiantes for at least one backbone atom (N,CA,C,O)\n"); - if(corruption&CRP_MULTICHAIN) - printf("File contains coordinates for multiple chains\n"); - if(corruption&CRP_MULTICA) - printf("Multiple CA atoms found for the same residue (could be alternate locators)\n"); - if(corruption&CRP_MULTICA) - printf("Multiple copies of backbone atoms found for the same residue (could be alternate locators)\n"); -} - /* sscanf(line, "%6s%5d%*1c%4s%1c%3s%*1c%1c%4d%1c%*3c%8lf%8lf%8lf%6lf%6lf%*6c%4s%2s%2s\n", - linetype,&aserial,aname,&altLoc,rname,&chainid,&rserial,&icode,&x,&y,&z,&opcy,&tmpt,segId,element,charge); - printf(".%s.%s.%s.\n",segId,element,charge); - printf("%-6s%5d%-1s%-4s%1c%3s%1s%1c%4d%1c%3s%8.3lf%8.3lf%8.3lf%6.2f%6.2f%6s%4s%2s%2s\n", - linetype,aserial," ",aname,altLoc,rname," ",chainid,rserial,icode," ",x,y,z,opcy,tmpt," ",segId,element,charge); */ - - /* and we could probably get away with this using astral files, */ - /* sscanf(line, "%6s%5d%*1c%4s%1c%3s%*1c%1c%4d%1c%*3c%8lf%8lf%8lf%6lf%6lf%*6c%6s\n", - linetype,&aserial,aname,&altLoc,rname,&chainid,&rserial,&icode,&x,&y,&z,&opcy,&tmpt,element); - printf("%-6s%5d%-1s%-4s%1c%3s%1s%1c%4d%1c%3s%8.3lf%8.3lf%8.3lf%6.2f%6.2f%6s%6s\n", - linetype,aserial," ",aname,altLoc,rname," ",chainid,rserial,icode," ",x,y,z,opcy,tmpt," ",element); */ diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/CMakeLists.txt b/3rdParty/metis/metis-5.1.0/GKlib/test/CMakeLists.txt deleted file mode 100644 index 372b0e2f43a22ce8cb0aa35e5b04d498ec88aeb9..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/test/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -# Where the header files reside -#include_directories(../) - -# Build program. -add_executable(strings strings.c) -add_executable(gksort gksort.c) -add_executable(fis fis.c) -add_executable(rw rw.c) -add_executable(gkgraph gkgraph.c) -foreach(prog strings gksort fis rw gkgraph) - target_link_libraries(${prog} GKlib) -endforeach(prog) - diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/Makefile.in.old b/3rdParty/metis/metis-5.1.0/GKlib/test/Makefile.in.old deleted file mode 100644 index cac4f523a6d4bf4df46b052249da0f3e644a4cbd..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/test/Makefile.in.old +++ /dev/null @@ -1,258 +0,0 @@ -#************************************************************************* -# Global flags -#************************************************************************* -gdb = yes -debug = no -memdbg = no -openmp = no -x86compiler = gcc - -VERNUM = 0.1.0 - - - -#************************************************************************* -# System-specific compilation flags -#************************************************************************* -# Get some basic information about the system that you are working on -cputype = $(shell uname -m | sed "s/\\ /_/g") -systype = $(shell uname) -ifeq ($(findstring CYGWIN, $(systype)),CYGWIN) -# systype = CYGWIN - systype = MSWIN - cputype = x86 -endif - - -GKLIBINCDIR = $(HOME)/work/algorithms/GKlib/trunk/ -GKLIBBUILDDIR = $(HOME)/work/algorithms/GKlib/builds/$(systype)-$(cputype) - - -ifeq ($(systype),MSWIN) - #------------------------------------------------------------------- - # These defs are very much Visual Studio Specific - #------------------------------------------------------------------- - #Compiler information - CC = cl - OPTFLAGS = /Ox - COPTIONS = -DWIN32 -DMSC -D_CRT_SECURE_NO_DEPRECATE - - #Compile input/output file specification - SOURCEFILE = /c $< - OUTPUTFILE = /Fo$@ - - #Output specification for executables - EXEOUTPUTFILE = /Fe$@ # This option is when cl is used for linking - #EXEOUTPUTFILE = /OUT:$@ # This option is used when link is used for linking - - #Linker information - LDOPTIONS = /MT - #LD = /cygdrive/c/Program\ Files/Microsoft\ Visual\ Studio\ 8/VC/BIN/link - LD = cl - MERGEMANIFEST = - - #Library creation information - AR = lib /OUT:$@ - RANLIB = - - ifeq ($(openmp),yes) - COPTIONS += -D__OPENMP__ /openmp - LDOPTIONS += /openmp - MERGEMANIFEST = vc_mt -manifest $@.manifest -outputresource:$@\;1 - endif - - #Library information - ifeq ($(cputype),i386) - LIBPLOTDIR = ../Libplot/Win32 - else - LIBPLOTDIR = ../Libplot/Win64 - endif - LIBS = $(LIBPLOTDIR)/libplot.lib $(BUILDDIR)/libcluto.lib $(GKLIBBUILDDIR)/libGKlib.lib - - # Standard file extensions - OBJEXT = .obj - LIBEXT = .lib - EXEEXT = .exe -else - ifeq ($(systype),Linux) - ifeq ($(x86compiler),gcc) - #Compiler information - CC = gcc - OPTFLAGS = -O6 - COPTIONS = -DLINUX -D_FILE_OFFSET_BITS=64 -pedantic -std=c99 -pthread - - #Linker information - LDOPTIONS = - LD = gcc - - MERGEMANIFEST = - - #Library creation information - AR = ar rv - RANLIB = ar -ts - else - #Compiler information - CC = icc - OPTFLAGS = -O3 - COPTIONS = -DLINUX -D_FILE_OFFSET_BITS=64 -std=c99 - - #Linker information - LDOPTIONS = - LD = icc - - #Library creation information - AR = ar rv - RANLIB = ar -ts - - ifeq ($(openmp),yes) - COPTIONS += -D__OPENMP__ -openmp -openmp-report2 - LDOPTIONS += -openmp - endif - endif - - #Library information - ifeq ($(cputype),x86_64) - LIBPLOTDIR = ../Libplot/Linux64 - else - LIBPLOTDIR = ../Libplot/Linux32 - endif - endif - - - ifeq ($(systype),SunOS) - #Compiler information - CC = /opt/SUNWspro/bin/cc - OPTFLAGS = -xO4 - COPTIONS =-DSUNOS - - #Linker information - LDOPTIONS = - LD = /opt/SUNWspro/bin/cc - - - #Library creation information - AR = ar rv - RANLIB = ar -ts - - #Library information - LIBPLOTDIR = ../Libplot/SunOS - endif - - - ifeq ($(systype),Darwin) - #Compiler information - CC = gcc - OPTFLAGS = -O6 - COPTIONS = -DDARWIN -D_FILE_OFFSET_BITS=64 -pedantic -std=c99 - - #Linker information - LDOPTIONS = -fvisibility=default - LD = gcc - - #Library creation information - AR = ar rv - RANLIB = ar -ts - - #Library information - ifeq ($(cputype),i386) - LIBPLOTDIR = ../Libplot/Darwini386 - else - LIBPLOTDIR = ../Libplot/DarwinPPC - endif - endif - - ifeq ($(systype),CYGWIN) - #Compiler information - CC = gcc - OPTFLAGS = -O6 - COPTIONS = -DCYGWIN -DWIN32 -D_FILE_OFFSET_BITS=64 -Wall -std=c99 -pedantic -mno-cygwin - - #Linker information - LDOPTIONS = -mno-cygwin - LD = gcc - - #Library creation information - AR = ar crv - RANLIB = ar -ts - - #Library information - LIBPLOTDIR = ../Libplot/CYGWIN - endif - - - #------------------------------------------------------------------- - # These defs are common among the GNU/GCC based systems - #------------------------------------------------------------------- - #Compile input/output file specification - SOURCEFILE = -c $< - OUTPUTFILE = -o $@ - - #Output specification for executables - EXEOUTPUTFILE = -o $@ - - #Library creation information - AR = ar crv $@ - RANLIB = ar -ts $@ - - #Libraries needed for linking - LIBSDIR = -L$(BUILDDIR) -L$(GKLIBBUILDDIR) -L$(HOME)/local/lib - LIBS = -lGKlib -lpcreposix -lpcre -lz -lm - - # Standard file extensions - OBJEXT = .o - LIBEXT = .a - EXEEXT = -endif - - -#************************************************************************** -DMALLOCINC = -DMALLOCFLAGS = -DEBUGFLAGS = - -ifeq ($(dmalloc),yes) - DMALLOCINC = -I$(HOME)/local/include - DMALLOCFLAGS = -DDMALLOC - OPTFLAGS = -g -endif - -ifeq ($(debug),yes) - DEBUGFLAGS = -DDEBUG - OPTFLAGS = -g -endif - -ifeq ($(gdb),yes) - OPTFLAGS += -g -endif -#************************************************************************** - - -#************************************************************************** -# Create the build directory if it does not exist -#************************************************************************** -ifeq ($(systype),Darwin) - BINDIR = $(HOME) -else - BINDIR = $(HOME)/work/bin/$(systype)-$(cputype) - $(shell mkdir -p $(BINDIR)) -endif - -ifeq ($(openmp),no) - BUILDDIR = ./builds/$(systype)-$(cputype) -else - BUILDDIR = ./builds/$(systype)-$(cputype)-openmp -endif - -LIBBUILDDIR = $(BUILDDIR)/lib -PRGBUILDDIR = $(BUILDDIR)/prg -$(shell mkdir -p $(BUILDDIR)) -$(shell mkdir -p $(LIBBUILDDIR)) -$(shell mkdir -p $(PRGBUILDDIR)) - - - - -INCLUDES = -I./ -I$(GKLIBINCDIR) -I$(LIBPLOTDIR) -I$(HOME)/local/include -CFLAGS = $(COPTIONS) $(OPTFLAGS) $(DEBUGFLAGS) $(INCLUDES) - - diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/Makefile.old b/3rdParty/metis/metis-5.1.0/GKlib/test/Makefile.old deleted file mode 100644 index 1ca357eef624229227c994ffe4fda9dd332a345d..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/test/Makefile.old +++ /dev/null @@ -1,39 +0,0 @@ -include Makefile.in - -STRINGSOBJS = $(PRGBUILDDIR)/strings$(OBJEXT) -GKSORTOBJS = $(PRGBUILDDIR)/gksort$(OBJEXT) -FISOBJS = $(PRGBUILDDIR)/fis$(OBJEXT) - -HEADERS = $(wildcard $(GKLIBINCDIR)/*.h) - - -default: $(BUILDDIR)/strings$(EXEEXT) $(BUILDDIR)/gksort$(EXEEXT) $(BUILDDIR)/fis$(EXEEXT) - - -$(BUILDDIR)/strings$(EXEEXT): $(STRINGSOBJS) $(GKLIBBUILDDIR)/libGKlib.a - $(LD) $(LDOPTIONS) $(EXEOUTPUTFILE) $(STRINGSOBJS) $(LIBSDIR) $(LIBS) ; $(MERGEMANIFEST) - chmod 744 $@ - -$(BUILDDIR)/gksort$(EXEEXT): $(GKSORTOBJS) $(GKLIBBUILDDIR)/libGKlib.a - $(LD) $(LDOPTIONS) $(EXEOUTPUTFILE) $(GKSORTOBJS) $(LIBSDIR) $(LIBS) ; $(MERGEMANIFEST) - chmod 744 $@ - -$(BUILDDIR)/fis$(EXEEXT): $(FISOBJS) $(GKLIBBUILDDIR)/libGKlib.a - $(LD) $(LDOPTIONS) $(EXEOUTPUTFILE) $(FISOBJS) $(LIBSDIR) $(LIBS) ; $(MERGEMANIFEST) - chmod 744 $@ - - -clean: - rm -rf $(PRGBUILDDIR) - -realclean: - rm -rf $(PRGBUILDDIR) ;\ - rm -rf $(BUILDDIR) ; - - -$(STRINGSOBJS) : $(HEADERS) Makefile.in Makefile $(GKLIBBUILDDIR)/libGKlib.a - - -$(PRGBUILDDIR)/%$(OBJEXT) : %.c - $(CC) $(CFLAGS) $(SOURCEFILE) $(OUTPUTFILE) - diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/gkgraph.c b/3rdParty/metis/metis-5.1.0/GKlib/test/gkgraph.c deleted file mode 100644 index 233620d9b99dfbf9f597f6b4171a989d216bce53..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/GKlib/test/gkgraph.c +++ /dev/null @@ -1,351 +0,0 @@ -/*! -\file -\brief A simple frequent itemset discovery program to test GKlib's routines - -\date 6/12/2008 -\author George -\version \verbatim $Id: gkgraph.c 11408 2012-01-25 15:05:58Z karypis $ \endverbatim -*/ - -#include <GKlib.h> - -/*************************************************************************/ -/*! Data structures for the code */ -/*************************************************************************/ -typedef struct { - int type; - int niter; - float eps; - float lamda; - - char *infile; - char *outfile; -} params_t; - -/*************************************************************************/ -/*! Constants */ -/*************************************************************************/ -#define CMD_NITER 1 -#define CMD_EPS 2 -#define CMD_LAMDA 3 -#define CMD_TYPE 4 -#define CMD_HELP 10 - - -/*************************************************************************/ -/*! Local variables */ -/*************************************************************************/ -static struct gk_option long_options[] = { - {"type", 1, 0, CMD_TYPE}, - {"niter", 1, 0, CMD_NITER}, - {"lamda", 1, 0, CMD_LAMDA}, - {"eps", 1, 0, CMD_EPS}, - {"help", 0, 0, CMD_HELP}, - {0, 0, 0, 0} -}; - - -/*-------------------------------------------------------------------*/ -/* Mini help */ -/*-------------------------------------------------------------------*/ -static char helpstr[][100] = { -" ", -"Usage: gkgraph [options] <graph-file> [<out-file>]", -" ", -" Required parameters", -" graph-file", -" The name of the file storing the graph. The file is in ", -" Metis' graph format.", -" ", -" Optional parameters", -" -niter=int", -" Specifies the maximum number of iterations. [default: 100]", -" ", -" -lamda=float", -" Specifies the follow-the-adjacent-links probability. [default: 0.80]", -" ", -" -eps=float", -" Specifies the error tollerance. [default: 1e-10]", -" ", -" -help", -" Prints this message.", -"" -}; - -static char shorthelpstr[][100] = { -" ", -" Usage: gkgraph [options] <graph-file> [<out-file>]", -" use 'gkgraph -help' for a summary of the options.", -"" -}; - - - -/*************************************************************************/ -/*! Function prototypes */ -/*************************************************************************/ -double compute_compactness(params_t *params, gk_graph_t *graph, int32_t *perm); -void reorder_centroid(params_t *params, gk_graph_t *graph, int32_t *perm); -void print_init_info(params_t *params, gk_graph_t *graph); -void print_final_info(params_t *params); -params_t *parse_cmdline(int argc, char *argv[]); - - -/*************************************************************************/ -/*! the entry point */ -/**************************************************************************/ -int main(int argc, char *argv[]) -{ - ssize_t i, j, v; - params_t *params; - gk_graph_t *graph, *pgraph; - int32_t *perm; - - /* get command-line options */ - params = parse_cmdline(argc, argv); - - /* read the data */ - graph = gk_graph_Read(params->infile, GK_GRAPH_FMT_METIS, 0, 0, 0); - - /* display some basic stats */ - print_init_info(params, graph); - - - /* determine the initial compactness of the graph */ - printf("Initial compactness: %le\n", compute_compactness(params, graph, NULL)); - - /* compute the BFS ordering and re-order the graph */ - //for (i=0; i<params->niter; i++) { - for (i=0; i<1; i++) { - v = RandomInRange(graph->nvtxs); - gk_graph_ComputeBFSOrdering(graph, v, &perm, NULL); - printf("BFS from %8d. Compactness: %le\n", - (int) v, compute_compactness(params, graph, perm)); - - pgraph = gk_graph_Reorder(graph, perm, NULL); - gk_graph_Write(pgraph, "bfs.metis", GK_GRAPH_FMT_METIS); - gk_graph_Free(&pgraph); - - gk_graph_ComputeBestFOrdering(graph, v, params->type, &perm, NULL); - printf("BestF from %8d. Compactness: %le\n", - (int) v, compute_compactness(params, graph, perm)); - - pgraph = gk_graph_Reorder(graph, perm, NULL); - gk_graph_Write(pgraph, "bestf.metis", GK_GRAPH_FMT_METIS); - gk_graph_Free(&pgraph); - -#ifdef XXX - for (j=0; j<params->niter; j++) { - reorder_centroid(params, graph, perm); - printf("\tAfter centroid; Compactness: %le\n", - compute_compactness(params, graph, perm)); - } - - pgraph = gk_graph_Reorder(graph, perm, NULL); - gk_graph_Write(pgraph, "centroid.metis", GK_GRAPH_FMT_METIS); - gk_graph_Free(&pgraph); -#endif - gk_free((void **)&perm, LTERM); - } - - gk_graph_Free(&graph); - //gk_graph_Free(&pgraph); - - print_final_info(params); -} - - - - -/*************************************************************************/ -/*! This function computes the compactness of the graph's adjacency list */ -/*************************************************************************/ -double compute_compactness(params_t *params, gk_graph_t *graph, int32_t *perm) -{ - int i, v, u, nvtxs; - ssize_t j, *xadj; - int32_t *adjncy; - double compactness=0.0; - int *freq; - - nvtxs = graph->nvtxs; - xadj = graph->xadj; - adjncy = graph->adjncy; - - freq = gk_ismalloc(nvtxs, 0, "compute_compactness: freq"); - - for (i=0; i<nvtxs; i++) { - v = (perm == NULL ? i : perm[i]); - for (j=xadj[i]; j<xadj[i+1]; j++) { - u = (perm == NULL ? adjncy[j] : perm[adjncy[j]]); - compactness += fabs(v-u); - freq[gk_abs(v-u)]++; - } - } - - /* - for (i=0; i<nvtxs; i++) { - if (freq[i] > 0) - printf("%7d %6d\n", i, freq[i]); - } - */ - printf("\tnsmall: %d\n", freq[1]+freq[2]+freq[3]); - - return compactness/xadj[nvtxs]; -} - - -/*************************************************************************/ -/*! This function uses a centroid-based approach to refine the ordering */ -/*************************************************************************/ -void reorder_centroid(params_t *params, gk_graph_t *graph, int32_t *perm) -{ - int i, v, u, nvtxs; - ssize_t j, *xadj; - int32_t *adjncy; - gk_fkv_t *cand; - double displacement; - - nvtxs = graph->nvtxs; - xadj = graph->xadj; - adjncy = graph->adjncy; - - cand = gk_fkvmalloc(nvtxs, "reorder_centroid: cand"); - - for (i=0; i<nvtxs; i++) { - v = perm[i]; - displacement = 0.0; - - for (j=xadj[i]; j<xadj[i+1]; j++) { - u = perm[adjncy[j]]; - displacement += u-v; - //displacement += sign(u-v, sqrt(fabs(u-v))); - } - - cand[i].val = i; - cand[i].key = v + displacement*params->lamda/(xadj[i+1]-xadj[i]); - } - - /* sort them based on the target position in increasing order */ - gk_fkvsorti(nvtxs, cand); - - - /* derive the permutation from the ordered list */ - gk_i32set(nvtxs, -1, perm); - for (i=0; i<nvtxs; i++) { - if (perm[cand[i].val] != -1) - errexit("Resetting perm[%d] = %d\n", cand[i].val, perm[cand[i].val]); - perm[cand[i].val] = i; - } - - gk_free((void **)&cand, LTERM); -} - - - - - - - - -/*************************************************************************/ -/*! This function prints run parameters */ -/*************************************************************************/ -void print_init_info(params_t *params, gk_graph_t *graph) -{ - printf("*******************************************************************************\n"); - printf(" gkgraph\n\n"); - printf("Graph Information ----------------------------------------------------------\n"); - printf(" input file=%s, [%d, %zd]\n", - params->infile, graph->nvtxs, graph->xadj[graph->nvtxs]); - - printf("\n"); - printf("Options --------------------------------------------------------------------\n"); - printf(" type=%d, niter=%d, lamda=%f, eps=%e\n", - params->type, params->niter, params->lamda, params->eps); - - printf("\n"); - printf("Working... -----------------------------------------------------------------\n"); -} - - -/*************************************************************************/ -/*! This function prints final statistics */ -/*************************************************************************/ -void print_final_info(params_t *params) -{ - printf("\n"); - printf("Memory Usage Information -----------------------------------------------------\n"); - printf(" Maximum memory used: %10zd bytes\n", (ssize_t) gk_GetMaxMemoryUsed()); - printf(" Current memory used: %10zd bytes\n", (ssize_t) gk_GetCurMemoryUsed()); - printf("********************************************************************************\n"); -} - - -/*************************************************************************/ -/*! This is the entry point of the command-line argument parser */ -/*************************************************************************/ -params_t *parse_cmdline(int argc, char *argv[]) -{ - int i; - int c, option_index; - params_t *params; - - params = (params_t *)gk_malloc(sizeof(params_t), "parse_cmdline: params"); - - /* initialize the params data structure */ - params->type = 1; - params->niter = 1; - params->eps = 1e-10; - params->lamda = 0.20; - params->infile = NULL; - - - /* Parse the command line arguments */ - while ((c = gk_getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { - switch (c) { - case CMD_TYPE: - if (gk_optarg) params->type = atoi(gk_optarg); - break; - case CMD_NITER: - if (gk_optarg) params->niter = atoi(gk_optarg); - break; - case CMD_EPS: - if (gk_optarg) params->eps = atof(gk_optarg); - break; - case CMD_LAMDA: - if (gk_optarg) params->lamda = atof(gk_optarg); - break; - - case CMD_HELP: - for (i=0; strlen(helpstr[i]) > 0; i++) - printf("%s\n", helpstr[i]); - exit(0); - break; - case '?': - default: - printf("Illegal command-line option(s)\nUse %s -help for a summary of the options.\n", argv[0]); - exit(0); - } - } - - if (argc-gk_optind != 1) { - printf("Unrecognized parameters."); - for (i=0; strlen(shorthelpstr[i]) > 0; i++) - printf("%s\n", shorthelpstr[i]); - exit(0); - } - - params->infile = gk_strdup(argv[gk_optind++]); - - if (argc-gk_optind > 0) - params->outfile = gk_strdup(argv[gk_optind++]); - else - params->outfile = gk_strdup("gkgraph.out"); - - if (!gk_fexists(params->infile)) - errexit("input file %s does not exist.\n", params->infile); - - return params; -} - diff --git a/3rdParty/metis/metis-5.1.0/libmetis/kmetis.c b/3rdParty/metis/metis-5.1.0/libmetis/kmetis.c deleted file mode 100644 index cb6d1afb3d50e86eee16247719d31d09b78a324c..0000000000000000000000000000000000000000 --- a/3rdParty/metis/metis-5.1.0/libmetis/kmetis.c +++ /dev/null @@ -1,243 +0,0 @@ -/*! -\file -\brief The top-level routines for multilevel k-way partitioning that minimizes - the edge cut. - -\date Started 7/28/1997 -\author George -\author Copyright 1997-2011, Regents of the University of Minnesota -\version\verbatim $Id: kmetis.c 13905 2013-03-25 13:21:20Z karypis $ \endverbatim -*/ - -#include "metislib.h" - - -/*************************************************************************/ -/*! This function is the entry point for MCKMETIS */ -/*************************************************************************/ -int METIS_PartGraphKway(idx_t *nvtxs, idx_t *ncon, idx_t *xadj, idx_t *adjncy, - idx_t *vwgt, idx_t *vsize, idx_t *adjwgt, idx_t *nparts, - real_t *tpwgts, real_t *ubvec, idx_t *options, idx_t *objval, - idx_t *part) -{ - int sigrval=0, renumber=0; - graph_t *graph; - ctrl_t *ctrl; - - /* set up malloc cleaning code and signal catchers */ - if (!gk_malloc_init()) - return METIS_ERROR_MEMORY; - - gk_sigtrap(); - - if ((sigrval = gk_sigcatch()) != 0) - goto SIGTHROW; - - - /* set up the run parameters */ - ctrl = SetupCtrl(METIS_OP_KMETIS, options, *ncon, *nparts, tpwgts, ubvec); - if (!ctrl) { - gk_siguntrap(); - return METIS_ERROR_INPUT; - } - - /* if required, change the numbering to 0 */ - if (ctrl->numflag == 1) { - Change2CNumbering(*nvtxs, xadj, adjncy); - renumber = 1; - } - - /* set up the graph */ - graph = SetupGraph(ctrl, *nvtxs, *ncon, xadj, adjncy, vwgt, vsize, adjwgt); - - /* set up multipliers for making balance computations easier */ - SetupKWayBalMultipliers(ctrl, graph); - - /* set various run parameters that depend on the graph */ - ctrl->CoarsenTo = gk_max((*nvtxs)/(20*gk_log2(*nparts)), 30*(*nparts)); - ctrl->nIparts = (ctrl->CoarsenTo == 30*(*nparts) ? 4 : 5); - - /* take care contiguity requests for disconnected graphs */ - if (ctrl->contig && !IsConnected(graph, 0)) - gk_errexit(SIGERR, "METIS Error: A contiguous partition is requested for a non-contiguous input graph.\n"); - - /* allocate workspace memory */ - AllocateWorkSpace(ctrl, graph); - - /* start the partitioning */ - IFSET(ctrl->dbglvl, METIS_DBG_TIME, InitTimers(ctrl)); - IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->TotalTmr)); - - *objval = MlevelKWayPartitioning(ctrl, graph, part); - - IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->TotalTmr)); - IFSET(ctrl->dbglvl, METIS_DBG_TIME, PrintTimers(ctrl)); - - /* clean up */ - FreeCtrl(&ctrl); - -SIGTHROW: - /* if required, change the numbering back to 1 */ - if (renumber) - Change2FNumbering(*nvtxs, xadj, adjncy, part); - - gk_siguntrap(); - gk_malloc_cleanup(0); - - return metis_rcode(sigrval); -} - - -/*************************************************************************/ -/*! This function computes a k-way partitioning of a graph that minimizes - the specified objective function. - - \param ctrl is the control structure - \param graph is the graph to be partitioned - \param part is the vector that on return will store the partitioning - - \returns the objective value of the partitoning. The partitioning - itself is stored in the part vector. -*/ -/*************************************************************************/ -idx_t MlevelKWayPartitioning(ctrl_t *ctrl, graph_t *graph, idx_t *part) -{ - idx_t i, j, objval=0, curobj=0, bestobj=0; - real_t curbal=0.0, bestbal=0.0; - graph_t *cgraph; - int status; - - - for (i=0; i<ctrl->ncuts; i++) { - cgraph = CoarsenGraph(ctrl, graph); - - IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); - AllocateKWayPartitionMemory(ctrl, cgraph); - - /* Release the work space */ - FreeWorkSpace(ctrl); - - /* Compute the initial partitioning */ - InitKWayPartitioning(ctrl, cgraph); - - /* Re-allocate the work space */ - AllocateWorkSpace(ctrl, graph); - AllocateRefinementWorkSpace(ctrl, 2*cgraph->nedges); - - IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); - IFSET(ctrl->dbglvl, METIS_DBG_IPART, - printf("Initial %"PRIDX"-way partitioning cut: %"PRIDX"\n", ctrl->nparts, objval)); - - RefineKWay(ctrl, graph, cgraph); - - switch (ctrl->objtype) { - case METIS_OBJTYPE_CUT: - curobj = graph->mincut; - break; - - case METIS_OBJTYPE_VOL: - curobj = graph->minvol; - break; - - default: - gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype); - } - - curbal = ComputeLoadImbalanceDiff(graph, ctrl->nparts, ctrl->pijbm, ctrl->ubfactors); - - if (i == 0 - || (curbal <= 0.0005 && bestobj > curobj) - || (bestbal > 0.0005 && curbal < bestbal)) { - icopy(graph->nvtxs, graph->where, part); - bestobj = curobj; - bestbal = curbal; - } - - FreeRData(graph); - - if (bestobj == 0) - break; - } - - FreeGraph(&graph); - - return bestobj; -} - - -/*************************************************************************/ -/*! This function computes the initial k-way partitioning using PMETIS -*/ -/*************************************************************************/ -void InitKWayPartitioning(ctrl_t *ctrl, graph_t *graph) -{ - idx_t i, ntrials, options[METIS_NOPTIONS], curobj=0, bestobj=0; - idx_t *bestwhere=NULL; - real_t *ubvec=NULL; - int status; - - METIS_SetDefaultOptions(options); - options[METIS_OPTION_NITER] = 10; - options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT; - options[METIS_OPTION_NO2HOP] = ctrl->no2hop; - - - ubvec = rmalloc(graph->ncon, "InitKWayPartitioning: ubvec"); - for (i=0; i<graph->ncon; i++) - ubvec[i] = (real_t)pow(ctrl->ubfactors[i], 1.0/log(ctrl->nparts)); - - - switch (ctrl->objtype) { - case METIS_OBJTYPE_CUT: - case METIS_OBJTYPE_VOL: - options[METIS_OPTION_NCUTS] = ctrl->nIparts; - status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, - graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, - graph->adjwgt, &ctrl->nparts, ctrl->tpwgts, ubvec, - options, &curobj, graph->where); - - if (status != METIS_OK) - gk_errexit(SIGERR, "Failed during initial partitioning\n"); - - break; - -#ifdef XXX /* This does not seem to help */ - case METIS_OBJTYPE_VOL: - bestwhere = imalloc(graph->nvtxs, "InitKWayPartitioning: bestwhere"); - options[METIS_OPTION_NCUTS] = 2; - - ntrials = (ctrl->nIparts+1)/2; - for (i=0; i<ntrials; i++) { - status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, - graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, - graph->adjwgt, &ctrl->nparts, ctrl->tpwgts, ubvec, - options, &curobj, graph->where); - if (status != METIS_OK) - gk_errexit(SIGERR, "Failed during initial partitioning\n"); - - curobj = ComputeVolume(graph, graph->where); - - if (i == 0 || bestobj > curobj) { - bestobj = curobj; - if (i < ntrials-1) - icopy(graph->nvtxs, graph->where, bestwhere); - } - - if (bestobj == 0) - break; - } - if (bestobj != curobj) - icopy(graph->nvtxs, bestwhere, graph->where); - - break; -#endif - - default: - gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype); - } - - gk_free((void **)&ubvec, &bestwhere, LTERM); - -} - - diff --git a/3rdParty/metis/metis-5.1.1/CMakeLists.txt b/3rdParty/metis/metis-5.1.1/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..dccc6b595f94ddd42161ecb7e741fe7aba79b40f --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/CMakeLists.txt @@ -0,0 +1,43 @@ +cmake_minimum_required(VERSION 3.0) +project(METIS C) + +set(GKLIB_PATH "${CMAKE_CURRENT_SOURCE_DIR}/GKlib") + +# Configure libmetis library. +if(BUILD_SHARED_LIBS) + set(METIS_LIBRARY_TYPE SHARED) +else() + set(METIS_LIBRARY_TYPE STATIC) +endif() + +include(${GKLIB_PATH}/GKlibSystem.cmake) + +# METIS' custom options +option(METIS_IDX64 "enable 64 bit ints" OFF) +option(METIS_REAL64 "enable 64 bit floats (i.e., double)" OFF) + +if(METIS_IDX64) + set(METIS_COPTIONS_IDX "-DIDXTYPEWIDTH=64") +else() + set(METIS_COPTIONS_IDX "-DIDXTYPEWIDTH=32") +endif() + +if(METIS_REAL64) + set(METIS_COPTIONS_REAL "-DREALTYPEWIDTH=64") +else() + set(METIS_COPTIONS_REAL "-DREALTYPEWIDTH=32") +endif() + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${METIS_COPTIONS_IDX} ${METIS_COPTIONS_REAL}") + + +add_subdirectory("libmetis") + +target_include_directories(metis PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/libmetis) +target_include_directories(metis PRIVATE ${GKLIB_PATH}) + +target_include_directories(metis PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) +target_compile_definitions(metis PUBLIC ${METIS_COPTIONS_IDX}) +target_compile_definitions(metis PUBLIC ${METIS_COPTIONS_REAL}) + +groupTarget(metis ${thirdFolder}) \ No newline at end of file diff --git a/3rdParty/metis/metis-5.1.1/Changelog b/3rdParty/metis/metis-5.1.1/Changelog new file mode 100644 index 0000000000000000000000000000000000000000..4b2db8865e9cbb4bc5c0ccbd49cceeb54f14b0a5 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/Changelog @@ -0,0 +1,286 @@ + +metis-5.1.0 +------------------------------------------------------------------------ +r13937 | karypis | 2013-03-29 23:08:21 -0500 (Fri, 29 Mar 2013) + +- Further extended the 2-hop coarsening scheme introduced in 5.0.2 for + for graphs with highly variable degree distribution (e.g., power-law). + This coarsening scheme is automatically used when the standard + 1-hop-based scheme leaves a large fraction of the vertices of the + graph unmatched. It leads to better quality partitionings, lower + memory utilization, and faster execution time. In principle, this + scheme will never be triggered for graphs/matrices appearing in + scientific computations derived from FE meshes. However, if you + notice that the quality of the solutions is significantly worse, + this 2-hop matching can be turned off by using the '-no2hop' command + line option and the associated options[] parameter (as described + in the manual). +- Fixed 0/1 numbering issue with mesh partitioning routines (flyspray + issue #109) + + +metis-5.0.3 +------------------------------------------------------------------------ +r13822 | karypis | 2013-03-11 14:40:11 -0500 (Mon, 11 Mar 2013) + +- Fixed the bug that was introduced in 5.x for creating nodal graphs + from meshes (flyspray issue #107). +- Changed the license to Apache Version 2. + + +metis-5.0.2 +------------------------------------------------------------------------ +r10974 | karypis | 2011-10-29 18:24:32 -0500 (Sat, 29 Oct 2011) + +- Fixed issue with high-degree vertices and mask-based compression. +- Fixed issue with wrong COARSENING_FRACTION. +- Modified coarsening schemes to better support non FE graphs. + + +metis-5.0.1 +------------------------------------------------------------------------ +r10709 | karypis | 2011-08-31 16:07:57 -0500 (Wed, 31 Aug 2011) + +- Fixed critical bug in the mesh partitioning routines. + + +metis-5.0 +------------------------------------------------------------------------ +r10667 | karypis | 2011-08-04 00:35:30 -0500 (Thu, 04 Aug 2011) + +- Updated/corrected error messages. +- Addressed some build issues. + + +metis-5.0rc3 +------------------------------------------------------------------------ +r10560 | karypis | 2011-07-13 08:19:10 -0500 (Wed, 13 Jul 2011) + +- Fixed various bugs that were identified by testers. +- Some minor performance and quality improvements. +- Addressed some build issues. + + +metis-5.0rc2 +------------------------------------------------------------------------ +r10496 | karypis | 2011-07-06 11:04:45 -0500 (Wed, 06 Jul 2011) + +- Various run-time and quality optimizations. +- Option error-checking. +- Signal-based heap cleanup on error. Metis API routines will not + return nicely and cleanup all memory that may have allocated. +- Reduced memory requirements. +- Fixed various bugs identified in rc1. +- Added back Fortran support in the form of alternate API names + (see libmetis/frename.h). +- Minor code changes to accommodate ParMetis 4.0. + + +metis-5.0rc1 +------------------------------------------------------------------------ +r10227 | karypis | 2011-06-13 23:35:05 -0500 (Mon, 13 Jun 2011) + +- A nearly complete re-write of Metis' code-based that changed expanded + the functionality of the command-line programs and API routines. +- Multi-constraint partitioning can be used in conjunction with + minimization of the total communication volume. +- All graph and mesh partitioning routines take as input the target + sizes of the partitions, which among others, allow them to compute + partitioning solutions that are well-suited for parallel architectures + with heterogeneous computing capabilities. +- When multi-constraint partitioning is used, the target sizes of the + partitions are specified on a per partition-constraint pair. +- The multilevel k-way partitioning algorithms can compute a + partitioning solution in which each partition is contiguous. +- All partitioning and ordering routines can compute multiple different + solutions and select the best as the final solution. +- The mesh partitioning and mesh-to-graph conversion routines can + operate on mixed element meshes. +- The command-line programs provide full access to the entire set of + capabilities provided by Metis' API. +- Re-written the memory management subsystem to reduce overall memory + requirements. + + + +metis-5.0pre2 +------------------------------------------------------------------------ +r1437 | karypis | 2007-04-07 23:16:16 -0500 (Sat, 07 Apr 2007) + +- Added installation instructions and change-logs. +- Tested 32bit & 64bit on 64bit architectures and passed tests. +- Tested 32bit on 32bit architectures and passed tests. +- strtoidx() addition for portable input file parsing +- Restructured the internal memory allocation schemes for graph and + refinement data. This should enhance portability and make the code + easier to maintain. +- Fixed some bad memory allocation calls (i.e., sizeof(x)/sizeof(idxtype). + However, there are tons of those and need to be corrected once and for + all by eliminating workspace and the associated mallocs. +- Added mprint/mscanf family of functions for portable formated I/O + of the idxtype datatype. The specifier for this datatype is %D. + All library routines use this function for printing. + The implementation of these routines is not very efficient, but + that should do for now (in principle these routines should not be + used unless debugging). +- Incorporated GKlib into METIS, which replaced many of its internal + functions. GKlib's malloc interface will enable graceful and clean + aborts (i.e., free all internally allocated memory) on fatal errors. + This will probably be available in the next pre-release. +- Fixed the problems associated with metis.h that were identified by + David (flyspray Issue #9). + + +METIS 4.0.2, 3/10/04 +------------------------------------------------------------------------------ +- Fixed a problem with weighted graphs and ometis.c + + +METIS 4.0.1, 11/29/98 +------------------------------------------------------------------------------ +This is mostly a bug-fix release + + - Fixed some bugs in the multi-constraint partitioning routines + - Fixed some bugs in the volume-minimization routines + + + +METIS 4.0.0, 9/20/98 +------------------------------------------------------------------------------ +METIS 4.0 contains a number of changes over the previous major release (ver +3.0.x). Most of these changes are concentrated on the graph and mesh +partitioning routines and they do not affect the sparse matrix re-ordering +routines. Here is a list of the major changes: + + Multi-Constraint Partitioning + ----------------------------- + METIS now includes partitioning routines that can be used to a partition + a graph in the presence of multiple balancing constraints. + + Minimizing the Total Communication Volume + ----------------------------------------- + METIS now includes partitioning routines whose objective is to minimize + the total communication volume (as opposed to minimizing the edge-cut). + + Minimizing the Maximum Connectivity of the Subdomains + ----------------------------------------------------- + The k-way partitioning routines in METIS can now directly minimize the number + of adjacent subdomains. For most graphs corresponding to finite element + meshes, METIS is able to significantly reduce the maximum (and total) number of + adjacent subdomains. + + + + +METIS 3.0.6, 1/28/98 +------------------------------------------------------------------------------- + - Fixed some problems when too many partitions were asked, and each partition + end up having 0 vertices + - Fixed some bugs in the I/O routines + - Added support for the g77 compiler under Linux + + +METIS 3.0.5, 12/22/97 +------------------------------------------------------------------------------- + - Fixed problems on 64-bit architectures (eg., -64 option on SGIs). + - Added some options in Makefile.in + + +METIS 3.0.4, 12/1/97 +------------------------------------------------------------------------------- + Fixed a memory leak in the ordering code. + + +METIS 3.0.3, 11/5/97 +------------------------------------------------------------------------------- + This is mostly a bug-fix release with just a few additions + + Added functionality + - Added support for quadrilateral elements. + - Added a routine METIS_EstimateMemory that estimates the amount of + memory that will be allocated by METIS. This is useful in determining + if a problem can run on your system. + - Added hooks to allow PARMETIS to use the orderings produced by METIS. + This is hidden from the user but it will be used in the next release + of PARMETIS. + + Bug-fixes + - Fixed a bug related to memory allocation. This should somewhat reduce the + overall memory used by METIS. + - Fixed some bugs in the 'graphchk' program in the case of weighted graphs. + - Removed some code corresponding to unused options. + - Fixed some minor bugs in the node-refinement code + + + +------------------------------------------------------------------------------- +METIS 3.0 contains a number of changes over METIS 2.0. +The major changes are the following: + + General Changes + --------------- + 1. Added code to directly partition finite element meshes. + + 2. Added code to convert finite element meshes into graphs so they + can be used by METIS. + + 1. The names, calling sequences, and options of the routines in + METISlib have been changed. + + 2. Better support has been added for Fortran programs. + + 3. Eliminated the 'metis' program. The only way to tune METIS's + behavior is to use METISlib. + + 4. Improved memory management. METIS should now only abort if truly + there is no more memory left in the system. + + + Graph Partitioning + ------------------ + 1. Added partitioning routines that can be used to compute a partition + with prescribed partition weights. For example, they can be used to + compute a 3-way partition such that partition 1 has 50% of the weight, + partition 2 has 20% of the way, and partition 3 has 30% of the weight. + + 2. Improved the speed of the k-way partitioning algorithm (kmetis). The + new code has better cache locality which dramatically improves the + speed for large graphs. A factor of 4 speedup can be obtained for + certain graphs. METIS can now partition a 4 million node graph + in well under a minute on a MIPS R10000. + + 3. Eliminated some of the options that were seldom used. + + + Fill-Reducing Orderings + ---------------------- + 1. Added a node based ordering code `onmetis' that greatly improves + ordering quality. + + 2. Improved the quality of the orderings produced by the original + edge-based ordering code (it is now called 'oemetis'). + + 3. METIS can now analyze the graph and try to compress together + nodes with identical sparsity pattern. For some problems, this + significantly reduces ordering time + + 4. METIS can now prune dense columns prior to ordering. This can be + helpful for LP matrices. + + + Mesh Partitioning + ----------------- + 1. METIS can now directly partition the element node array of finite + element meshes. It produces two partitioning vectors. One for the + elements and one for the nodes. METIS supports the following + elements: triangles, tetrahedra, hexahedra + + + Mesh-To-Graph Conversion Routines + --------------------------------- + 1. METIS now includes a number of mesh conversion functions that can + be used to create the dual and nodal graphs directly from the + element connectivity arrays. These are highly optimized routines. + + + diff --git a/3rdParty/metis/metis-5.1.1/GKlib/.gitignore b/3rdParty/metis/metis-5.1.1/GKlib/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..80d93c4c3befef2d3a5e4368727bc070f0683274 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/.gitignore @@ -0,0 +1,57 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# GK things +build/ +lib/ +.svn/ diff --git a/3rdParty/metis/metis-5.1.1/GKlib/CMakeLists.txt b/3rdParty/metis/metis-5.1.1/GKlib/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9cd1b4bfaa8194c325558869618c565f214a0812 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/CMakeLists.txt @@ -0,0 +1,31 @@ +cmake_minimum_required(VERSION 2.8) +project(GKlib C) + +option(BUILD_SHARED_LIBS "Build shared libraries (.dll/.so) instead of static ones (.lib/.a)" OFF) + +get_filename_component(abs "." ABSOLUTE) +set(GKLIB_PATH ${abs}) +unset(abs) +include(GKlibSystem.cmake) + +include_directories(".") +if(MSVC) + include_directories("win32") + file(GLOB win32_sources RELATIVE "win32" "*.c") +else(MSVC) + set(win32_sources, "") +endif(MSVC) + +add_library(GKlib ${GKlib_sources} ${win32_sources}) + +if(UNIX) + target_link_libraries(GKlib m) +endif(UNIX) + +include_directories("test") +add_subdirectory("test") + +install(TARGETS GKlib + ARCHIVE DESTINATION lib/${LINSTALL_PATH} + LIBRARY DESTINATION lib/${LINSTALL_PATH}) +install(FILES ${GKlib_includes} DESTINATION include/${HINSTALL_PATH}) diff --git a/3rdParty/metis/metis-5.1.0/GKlib/GKlib.h b/3rdParty/metis/metis-5.1.1/GKlib/GKlib.h similarity index 95% rename from 3rdParty/metis/metis-5.1.0/GKlib/GKlib.h rename to 3rdParty/metis/metis-5.1.1/GKlib/GKlib.h index 492c90f2e84fc0f5fd2b12bcbb09f0068289625d..9278fe414f15236687a9ce11e27c8b32112b0d04 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/GKlib.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/GKlib.h @@ -3,7 +3,7 @@ * * George's library of most frequently used routines * - * $Id: GKlib.h 13005 2012-10-23 22:34:36Z karypis $ + * $Id: GKlib.h 14866 2013-08-03 16:40:04Z karypis $ * */ @@ -30,6 +30,7 @@ #include <stdlib.h> #include <stdarg.h> #include <stdio.h> +#include <memory.h> #include <errno.h> #include <ctype.h> #include <math.h> diff --git a/3rdParty/metis/metis-5.1.0/GKlib/GKlibSystem.cmake b/3rdParty/metis/metis-5.1.1/GKlib/GKlibSystem.cmake similarity index 80% rename from 3rdParty/metis/metis-5.1.0/GKlib/GKlibSystem.cmake rename to 3rdParty/metis/metis-5.1.1/GKlib/GKlibSystem.cmake index 86aef59c88dd6e02c669c38baae49d4c10198d74..d83b2083c176a3addb3ddb951fd0e44923b18aa6 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/GKlibSystem.cmake +++ b/3rdParty/metis/metis-5.1.1/GKlib/GKlibSystem.cmake @@ -3,15 +3,16 @@ include(CheckFunctionExists) include(CheckIncludeFile) # Setup options. -#option(GDB "enable use of GDB" OFF) -#option(ASSERT "turn asserts on" OFF) -#option(ASSERT2 "additional assertions" OFF) -#option(DEBUG "add debugging support" OFF) -#option(GPROF "add gprof support" OFF) -#option(OPENMP "enable OpenMP support" OFF) -#option(PCRE "enable PCRE support" OFF) -#option(GKREGEX "enable GKREGEX support" OFF) -#option(GKRAND "enable GKRAND support" OFF) +option(GDB "enable use of GDB" OFF) +option(ASSERT "turn asserts on" OFF) +option(ASSERT2 "additional assertions" OFF) +option(DEBUG "add debugging support" OFF) +option(GPROF "add gprof support" OFF) +option(OPENMP "enable OpenMP support" OFF) +option(PCRE "enable PCRE support" OFF) +option(GKREGEX "enable GKREGEX support" OFF) +option(GKRAND "enable GKRAND support" OFF) + # Add compiler flags. if(MSVC) @@ -20,7 +21,6 @@ if(MSVC) elseif(MINGW) set(GKlib_COPTS "-DUSE_GKREGEX") else() - set(GKlib_COPTS "-O3") set(GKlib_COPTIONS "-DLINUX -D_FILE_OFFSET_BITS=64") endif(MSVC) if(CYGWIN) @@ -29,16 +29,22 @@ endif(CYGWIN) if(CMAKE_COMPILER_IS_GNUCC) # GCC opts. set(GKlib_COPTIONS "${GKlib_COPTIONS} -std=c99 -fno-strict-aliasing") + set(GKlib_COPTIONS "${GKlib_COPTIONS} -march=native") if(NOT MINGW) set(GKlib_COPTIONS "${GKlib_COPTIONS} -fPIC") endif(NOT MINGW) # GCC warnings. - set(GKlib_COPTIONS "${GKlib_COPTIONS} -Wall -pedantic -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unknown-pragmas") + set(GKlib_COPTIONS "${GKlib_COPTIONS} -Werror -Wall -pedantic -Wno-unused-function -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unknown-pragmas -Wno-unused-label") elseif(${CMAKE_C_COMPILER_ID} MATCHES "Sun") # Sun insists on -xc99. set(GKlib_COPTIONS "${GKlib_COPTIONS} -xc99") endif(CMAKE_COMPILER_IS_GNUCC) +# Intel compiler +if(${CMAKE_C_COMPILER_ID} MATCHES "Intel") + set(GKlib_COPTIONS "${GKlib_COPTIONS} -xHost -std=c99") +endif() + # Find OpenMP if it is requested. if(OPENMP) include(FindOpenMP) @@ -54,6 +60,8 @@ endif(OPENMP) if(GDB) set(GKlib_COPTS "${GKlib_COPTS} -g") set(GKlib_COPTIONS "${GKlib_COPTIONS} -Werror") +else() + set(GKlib_COPTS "-O3") endif(GDB) @@ -104,7 +112,7 @@ endif(HAVE_GETLINE) # Custom check for TLS. if(MSVC) set(GKlib_COPTIONS "${GKlib_COPTIONS} -D__thread=__declspec(thread)") -else() + # This if checks if that value is cached or not. if("${HAVE_THREADLOCALSTORAGE}" MATCHES "^${HAVE_THREADLOCALSTORAGE}$") try_compile(HAVE_THREADLOCALSTORAGE diff --git a/3rdParty/metis/metis-5.1.1/GKlib/LICENSE.txt b/3rdParty/metis/metis-5.1.1/GKlib/LICENSE.txt new file mode 100644 index 0000000000000000000000000000000000000000..b61ca6f497f4ba23a172c5e59ef7bac86f455bf5 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/LICENSE.txt @@ -0,0 +1,18 @@ + +Copyright & License Notice +--------------------------- + +Copyright 1995-2018, Regents of the University of Minnesota + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/Makefile b/3rdParty/metis/metis-5.1.1/GKlib/Makefile similarity index 93% rename from 3rdParty/metis/metis-5.1.0/GKlib/Makefile rename to 3rdParty/metis/metis-5.1.1/GKlib/Makefile index d17b4f44c9621fcebdfa09a1378c7f842540959d..c9543d44c235acb693326d0fa0c35c863fc105f3 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/Makefile +++ b/3rdParty/metis/metis-5.1.1/GKlib/Makefile @@ -1,11 +1,12 @@ # Configuration options. +cc = gcc +prefix = ~/local +openmp = not-set gdb = not-set assert = not-set assert2 = not-set debug = not-set gprof = not-set -openmp = not-set -prefix = not-set pcre = not-set gkregex = not-set gkrand = not-set @@ -49,6 +50,9 @@ endif ifneq ($(prefix), not-set) CONFIG_FLAGS += -DCMAKE_INSTALL_PREFIX=$(prefix) endif +ifneq ($(cc), not-set) + CONFIG_FLAGS += -DCMAKE_C_COMPILER=$(cc) +endif define run-config mkdir -p $(BUILDDIR) diff --git a/3rdParty/metis/metis-5.1.1/GKlib/README.md b/3rdParty/metis/metis-5.1.1/GKlib/README.md new file mode 100644 index 0000000000000000000000000000000000000000..f94eeea36602d747e51df098c0b2f106b3a79b0b --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/README.md @@ -0,0 +1,54 @@ +# GKlib +A library of various helper routines and frameworks used by many of the lab's software + +## Build requirements + - CMake 2.8, found at http://www.cmake.org/, as well as GNU make. + +Assuming that the above are available, two commands should suffice to +build the software: +``` +make config +make +``` + +## Configuring the build +It is primarily configured by passing options to make config. For example: +``` +make config cc=icc +``` + +would configure it to be built using icc. + +Configuration options are: +``` +cc=[compiler] - The C compiler to use [default: gcc] +prefix=[PATH] - Set the installation prefix [default: ~/local] +openmp=set - To build a version with OpenMP support +``` + + +## Building and installing +To build and install, run the following +``` +make +make install +``` + +By default, the library file, header file, and binaries will be installed in +``` +~/local/lib +~/local/include +~/local/bin +``` + +## Other make commands + make uninstall + Removes all files installed by 'make install'. + + make clean + Removes all object files but retains the configuration options. + + make distclean + Performs clean and completely removes the build directory. + + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/b64.c b/3rdParty/metis/metis-5.1.1/GKlib/b64.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/b64.c rename to 3rdParty/metis/metis-5.1.1/GKlib/b64.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/blas.c b/3rdParty/metis/metis-5.1.1/GKlib/blas.c similarity index 91% rename from 3rdParty/metis/metis-5.1.0/GKlib/blas.c rename to 3rdParty/metis/metis-5.1.1/GKlib/blas.c index b65cd02648720536ff6412f0b4ac3320fc865fcc..a0b95ca7adfc481edb3ad1c3d93e46954964a887 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/blas.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/blas.c @@ -12,7 +12,7 @@ which is used for code generation. \date Started 9/28/95 \author George -\version\verbatim $Id: blas.c 11848 2012-04-20 13:47:37Z karypis $ \endverbatim +\version\verbatim $Id: blas.c 14330 2013-05-18 12:15:15Z karypis $ \endverbatim */ #include <GKlib.h> @@ -27,6 +27,7 @@ GK_MKBLAS(gk_i, int, int) GK_MKBLAS(gk_i32, int32_t, int32_t) GK_MKBLAS(gk_i64, int64_t, int64_t) GK_MKBLAS(gk_z, ssize_t, ssize_t) +GK_MKBLAS(gk_zu, size_t, size_t) GK_MKBLAS(gk_f, float, float) GK_MKBLAS(gk_d, double, double) GK_MKBLAS(gk_idx, gk_idx_t, gk_idx_t) diff --git a/3rdParty/metis/metis-5.1.1/GKlib/cache.c b/3rdParty/metis/metis-5.1.1/GKlib/cache.c new file mode 100644 index 0000000000000000000000000000000000000000..932e36d91b5081607e873819d062efef192da597 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/cache.c @@ -0,0 +1,126 @@ +/*! +\file +\brief Functions dealing with simulating cache behavior for performance + modeling and analysis; + +\date Started 4/13/18 +\author George +\author Copyright 1997-2011, Regents of the University of Minnesota +\version $Id: cache.c 21991 2018-04-16 03:08:12Z karypis $ +*/ + +#include <GKlib.h> + + +/*************************************************************************/ +/*! This function creates a cache + */ +/*************************************************************************/ +gk_cache_t *gk_cacheCreate(uint32_t nway, uint32_t lnbits, size_t cnbits) +{ + gk_cache_t *cache; + + cache = (gk_cache_t *)gk_malloc(sizeof(gk_cache_t), "gk_cacheCreate: cache"); + memset(cache, 0, sizeof(gk_cache_t)); + + cache->nway = nway; + cache->lnbits = lnbits; + cache->cnbits = cnbits; + cache->csize = 1<<cnbits; + cache->cmask = cache->csize-1; + + cache->latimes = gk_ui64smalloc(cache->csize*nway, 0, "gk_cacheCreate: latimes"); + cache->clines = gk_zusmalloc(cache->csize*nway, 0, "gk_cacheCreate: clines"); + + return cache; +} + + +/*************************************************************************/ +/*! This function resets a cache + */ +/*************************************************************************/ +void gk_cacheReset(gk_cache_t *cache) +{ + cache->nhits = 0; + cache->nmisses = 0; + + gk_ui64set(cache->csize*cache->nway, 0, cache->latimes); + gk_zuset(cache->csize*cache->nway, 0, cache->clines); + + return; +} + + +/*************************************************************************/ +/*! This function destroys a cache. + */ +/*************************************************************************/ +void gk_cacheDestroy(gk_cache_t **r_cache) +{ + gk_cache_t *cache = *r_cache; + + if (cache == NULL) + return; + + gk_free((void **)&cache->clines, &cache->latimes, &cache, LTERM); + + *r_cache = NULL; +} + + +/*************************************************************************/ +/*! This function simulates a load(ptr) operation. + */ +/*************************************************************************/ +int gk_cacheLoad(gk_cache_t *cache, size_t addr) +{ + uint32_t i, nway=cache->nway; + size_t lru=0; + + //printf("%16"PRIx64" ", (uint64_t)addr); + addr = addr>>(cache->lnbits); + //printf("%16"PRIx64" %16"PRIx64" %16"PRIx64" ", (uint64_t)addr, (uint64_t)addr&(cache->cmask), (uint64_t)cache->cmask); + + size_t *clines = cache->clines + (addr&(cache->cmask)); + uint64_t *latimes = cache->latimes + (addr&(cache->cmask)); + + cache->clock++; + for (i=0; i<nway; i++) { /* look for hits */ + if (clines[i] == addr) { + cache->nhits++; + latimes[i] = cache->clock; + goto DONE; + } + } + + for (i=0; i<nway; i++) { /* look for empty spots or the lru spot */ + if (clines[i] == 0) { + lru = i; + break; + } + else if (latimes[i] < latimes[lru]) { + lru = i; + } + } + + /* initial fill or replace */ + cache->nmisses++; + clines[lru] = addr; + latimes[lru] = cache->clock; + +DONE: + //printf(" %"PRIu64" %"PRIu64"\n", cache->nhits, cache->clock); + return 1; +} + + +/*************************************************************************/ +/*! This function returns the cache's hitrate + */ +/*************************************************************************/ +double gk_cacheGetHitRate(gk_cache_t *cache) +{ + return ((double)cache->nhits)/((double)(cache->clock+1)); +} + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/conf/check_thread_storage.c b/3rdParty/metis/metis-5.1.1/GKlib/conf/check_thread_storage.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/conf/check_thread_storage.c rename to 3rdParty/metis/metis-5.1.1/GKlib/conf/check_thread_storage.c diff --git a/3rdParty/metis/metis-5.1.1/GKlib/csr.c b/3rdParty/metis/metis-5.1.1/GKlib/csr.c new file mode 100644 index 0000000000000000000000000000000000000000..7e92a0c31377a0125525ee6633f17efc1847ec92 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/csr.c @@ -0,0 +1,3378 @@ +/*! + * \file + * + * \brief Various routines with dealing with CSR matrices + * + * \author George Karypis + * \version\verbatim $Id: csr.c 21044 2017-05-24 22:50:32Z karypis $ \endverbatim + */ + +#include <GKlib.h> + +#define OMPMINOPS 50000 + +/*************************************************************************/ +/*! Allocate memory for a CSR matrix and initializes it + \returns the allocated matrix. The various fields are set to NULL. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_Create() +{ + gk_csr_t *mat=NULL; + + if ((mat = (gk_csr_t *)gk_malloc(sizeof(gk_csr_t), "gk_csr_Create: mat"))) + gk_csr_Init(mat); + + return mat; +} + + +/*************************************************************************/ +/*! Initializes the matrix + \param mat is the matrix to be initialized. +*/ +/*************************************************************************/ +void gk_csr_Init(gk_csr_t *mat) +{ + memset(mat, 0, sizeof(gk_csr_t)); + mat->nrows = mat->ncols = 0; +} + + +/*************************************************************************/ +/*! Frees all the memory allocated for matrix. + \param mat is the matrix to be freed. +*/ +/*************************************************************************/ +void gk_csr_Free(gk_csr_t **mat) +{ + if (*mat == NULL) + return; + gk_csr_FreeContents(*mat); + gk_free((void **)mat, LTERM); +} + + +/*************************************************************************/ +/*! Frees only the memory allocated for the matrix's different fields and + sets them to NULL. + \param mat is the matrix whose contents will be freed. +*/ +/*************************************************************************/ +void gk_csr_FreeContents(gk_csr_t *mat) +{ + gk_free((void *)&mat->rowptr, &mat->rowind, &mat->rowval, + &mat->rowids, &mat->rlabels, &mat->rmap, + &mat->colptr, &mat->colind, &mat->colval, + &mat->colids, &mat->clabels, &mat->cmap, + &mat->rnorms, &mat->cnorms, &mat->rsums, &mat->csums, + &mat->rsizes, &mat->csizes, &mat->rvols, &mat->cvols, + &mat->rwgts, &mat->cwgts, + LTERM); +} + + +/*************************************************************************/ +/*! Returns a copy of a matrix. + \param mat is the matrix to be duplicated. + \returns the newly created copy of the matrix. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_Dup(gk_csr_t *mat) +{ + gk_csr_t *nmat; + + nmat = gk_csr_Create(); + + nmat->nrows = mat->nrows; + nmat->ncols = mat->ncols; + + /* copy the row structure */ + if (mat->rowptr) + nmat->rowptr = gk_zcopy(mat->nrows+1, mat->rowptr, + gk_zmalloc(mat->nrows+1, "gk_csr_Dup: rowptr")); + if (mat->rowids) + nmat->rowids = gk_icopy(mat->nrows, mat->rowids, + gk_imalloc(mat->nrows, "gk_csr_Dup: rowids")); + if (mat->rlabels) + nmat->rlabels = gk_icopy(mat->nrows, mat->rlabels, + gk_imalloc(mat->nrows, "gk_csr_Dup: rlabels")); + if (mat->rnorms) + nmat->rnorms = gk_fcopy(mat->nrows, mat->rnorms, + gk_fmalloc(mat->nrows, "gk_csr_Dup: rnorms")); + if (mat->rsums) + nmat->rsums = gk_fcopy(mat->nrows, mat->rsums, + gk_fmalloc(mat->nrows, "gk_csr_Dup: rsums")); + if (mat->rsizes) + nmat->rsizes = gk_fcopy(mat->nrows, mat->rsizes, + gk_fmalloc(mat->nrows, "gk_csr_Dup: rsizes")); + if (mat->rvols) + nmat->rvols = gk_fcopy(mat->nrows, mat->rvols, + gk_fmalloc(mat->nrows, "gk_csr_Dup: rvols")); + if (mat->rwgts) + nmat->rwgts = gk_fcopy(mat->nrows, mat->rwgts, + gk_fmalloc(mat->nrows, "gk_csr_Dup: rwgts")); + if (mat->rowind) + nmat->rowind = gk_icopy(mat->rowptr[mat->nrows], mat->rowind, + gk_imalloc(mat->rowptr[mat->nrows], "gk_csr_Dup: rowind")); + if (mat->rowval) + nmat->rowval = gk_fcopy(mat->rowptr[mat->nrows], mat->rowval, + gk_fmalloc(mat->rowptr[mat->nrows], "gk_csr_Dup: rowval")); + + /* copy the col structure */ + if (mat->colptr) + nmat->colptr = gk_zcopy(mat->ncols+1, mat->colptr, + gk_zmalloc(mat->ncols+1, "gk_csr_Dup: colptr")); + if (mat->colids) + nmat->colids = gk_icopy(mat->ncols, mat->colids, + gk_imalloc(mat->ncols, "gk_csr_Dup: colids")); + if (mat->clabels) + nmat->clabels = gk_icopy(mat->ncols, mat->clabels, + gk_imalloc(mat->ncols, "gk_csr_Dup: clabels")); + if (mat->cnorms) + nmat->cnorms = gk_fcopy(mat->ncols, mat->cnorms, + gk_fmalloc(mat->ncols, "gk_csr_Dup: cnorms")); + if (mat->csums) + nmat->csums = gk_fcopy(mat->ncols, mat->csums, + gk_fmalloc(mat->ncols, "gk_csr_Dup: csums")); + if (mat->csizes) + nmat->csizes = gk_fcopy(mat->ncols, mat->csizes, + gk_fmalloc(mat->ncols, "gk_csr_Dup: csizes")); + if (mat->cvols) + nmat->cvols = gk_fcopy(mat->ncols, mat->cvols, + gk_fmalloc(mat->ncols, "gk_csr_Dup: cvols")); + if (mat->cwgts) + nmat->cwgts = gk_fcopy(mat->ncols, mat->cwgts, + gk_fmalloc(mat->ncols, "gk_csr_Dup: cwgts")); + if (mat->colind) + nmat->colind = gk_icopy(mat->colptr[mat->ncols], mat->colind, + gk_imalloc(mat->colptr[mat->ncols], "gk_csr_Dup: colind")); + if (mat->colval) + nmat->colval = gk_fcopy(mat->colptr[mat->ncols], mat->colval, + gk_fmalloc(mat->colptr[mat->ncols], "gk_csr_Dup: colval")); + + return nmat; +} + + +/*************************************************************************/ +/*! Returns a submatrix containint a set of consecutive rows. + \param mat is the original matrix. + \param rstart is the starting row. + \param nrows is the number of rows from rstart to extract. + \returns the row structure of the newly created submatrix. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_ExtractSubmatrix(gk_csr_t *mat, int rstart, int nrows) +{ + ssize_t i; + gk_csr_t *nmat; + + if (rstart+nrows > mat->nrows) + return NULL; + + nmat = gk_csr_Create(); + + nmat->nrows = nrows; + nmat->ncols = mat->ncols; + + /* copy the row structure */ + if (mat->rowptr) + nmat->rowptr = gk_zcopy(nrows+1, mat->rowptr+rstart, + gk_zmalloc(nrows+1, "gk_csr_ExtractSubmatrix: rowptr")); + for (i=nrows; i>=0; i--) + nmat->rowptr[i] -= nmat->rowptr[0]; + ASSERT(nmat->rowptr[0] == 0); + + if (mat->rowids) + nmat->rowids = gk_icopy(nrows, mat->rowids+rstart, + gk_imalloc(nrows, "gk_csr_ExtractSubmatrix: rowids")); + if (mat->rnorms) + nmat->rnorms = gk_fcopy(nrows, mat->rnorms+rstart, + gk_fmalloc(nrows, "gk_csr_ExtractSubmatrix: rnorms")); + + if (mat->rsums) + nmat->rsums = gk_fcopy(nrows, mat->rsums+rstart, + gk_fmalloc(nrows, "gk_csr_ExtractSubmatrix: rsums")); + + ASSERT(nmat->rowptr[nrows] == mat->rowptr[rstart+nrows]-mat->rowptr[rstart]); + if (mat->rowind) + nmat->rowind = gk_icopy(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], + mat->rowind+mat->rowptr[rstart], + gk_imalloc(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], + "gk_csr_ExtractSubmatrix: rowind")); + if (mat->rowval) + nmat->rowval = gk_fcopy(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], + mat->rowval+mat->rowptr[rstart], + gk_fmalloc(mat->rowptr[rstart+nrows]-mat->rowptr[rstart], + "gk_csr_ExtractSubmatrix: rowval")); + + return nmat; +} + + +/*************************************************************************/ +/*! Returns a submatrix containing a certain set of rows. + \param mat is the original matrix. + \param nrows is the number of rows to extract. + \param rind is the set of row numbers to extract. + \returns the row structure of the newly created submatrix. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_ExtractRows(gk_csr_t *mat, int nrows, int *rind) +{ + ssize_t i, ii, j, nnz; + gk_csr_t *nmat; + + nmat = gk_csr_Create(); + + nmat->nrows = nrows; + nmat->ncols = mat->ncols; + + for (nnz=0, i=0; i<nrows; i++) + nnz += mat->rowptr[rind[i]+1]-mat->rowptr[rind[i]]; + + nmat->rowptr = gk_zmalloc(nmat->nrows+1, "gk_csr_ExtractPartition: rowptr"); + nmat->rowind = gk_imalloc(nnz, "gk_csr_ExtractPartition: rowind"); + nmat->rowval = gk_fmalloc(nnz, "gk_csr_ExtractPartition: rowval"); + + nmat->rowptr[0] = 0; + for (nnz=0, j=0, ii=0; ii<nrows; ii++) { + i = rind[ii]; + gk_icopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowind+mat->rowptr[i], nmat->rowind+nnz); + gk_fcopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowval+mat->rowptr[i], nmat->rowval+nnz); + nnz += mat->rowptr[i+1]-mat->rowptr[i]; + nmat->rowptr[++j] = nnz; + } + ASSERT(j == nmat->nrows); + + return nmat; +} + + +/*************************************************************************/ +/*! Returns a submatrix corresponding to a specified partitioning of rows. + \param mat is the original matrix. + \param part is the partitioning vector of the rows. + \param pid is the partition ID that will be extracted. + \returns the row structure of the newly created submatrix. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_ExtractPartition(gk_csr_t *mat, int *part, int pid) +{ + ssize_t i, j, nnz; + gk_csr_t *nmat; + + nmat = gk_csr_Create(); + + nmat->nrows = 0; + nmat->ncols = mat->ncols; + + for (nnz=0, i=0; i<mat->nrows; i++) { + if (part[i] == pid) { + nmat->nrows++; + nnz += mat->rowptr[i+1]-mat->rowptr[i]; + } + } + + nmat->rowptr = gk_zmalloc(nmat->nrows+1, "gk_csr_ExtractPartition: rowptr"); + nmat->rowind = gk_imalloc(nnz, "gk_csr_ExtractPartition: rowind"); + nmat->rowval = gk_fmalloc(nnz, "gk_csr_ExtractPartition: rowval"); + + nmat->rowptr[0] = 0; + for (nnz=0, j=0, i=0; i<mat->nrows; i++) { + if (part[i] == pid) { + gk_icopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowind+mat->rowptr[i], nmat->rowind+nnz); + gk_fcopy(mat->rowptr[i+1]-mat->rowptr[i], mat->rowval+mat->rowptr[i], nmat->rowval+nnz); + nnz += mat->rowptr[i+1]-mat->rowptr[i]; + nmat->rowptr[++j] = nnz; + } + } + ASSERT(j == nmat->nrows); + + return nmat; +} + + +/*************************************************************************/ +/*! Splits the matrix into multiple sub-matrices based on the provided + color array. + \param mat is the original matrix. + \param color is an array of size equal to the number of non-zeros + in the matrix (row-wise structure). The matrix is split into + as many parts as the number of colors. For meaningfull results, + the colors should be numbered consecutively starting from 0. + \returns an array of matrices for each supplied color number. +*/ +/**************************************************************************/ +gk_csr_t **gk_csr_Split(gk_csr_t *mat, int *color) +{ + ssize_t i, j; + int nrows, ncolors; + ssize_t *rowptr; + int *rowind; + float *rowval; + gk_csr_t **smats; + + nrows = mat->nrows; + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + + ncolors = gk_imax(rowptr[nrows], color, 1)+1; + + smats = (gk_csr_t **)gk_malloc(sizeof(gk_csr_t *)*ncolors, "gk_csr_Split: smats"); + for (i=0; i<ncolors; i++) { + smats[i] = gk_csr_Create(); + smats[i]->nrows = mat->nrows; + smats[i]->ncols = mat->ncols; + smats[i]->rowptr = gk_zsmalloc(nrows+1, 0, "gk_csr_Split: smats[i]->rowptr"); + } + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + smats[color[j]]->rowptr[i]++; + } + for (i=0; i<ncolors; i++) + MAKECSR(j, nrows, smats[i]->rowptr); + + for (i=0; i<ncolors; i++) { + smats[i]->rowind = gk_imalloc(smats[i]->rowptr[nrows], "gk_csr_Split: smats[i]->rowind"); + smats[i]->rowval = gk_fmalloc(smats[i]->rowptr[nrows], "gk_csr_Split: smats[i]->rowval"); + } + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + smats[color[j]]->rowind[smats[color[j]]->rowptr[i]] = rowind[j]; + smats[color[j]]->rowval[smats[color[j]]->rowptr[i]] = rowval[j]; + smats[color[j]]->rowptr[i]++; + } + } + + for (i=0; i<ncolors; i++) + SHIFTCSR(j, nrows, smats[i]->rowptr); + + return smats; +} + + +/**************************************************************************/ +/*! Determines the format of the CSR matrix based on the extension. + \param filename is the name of the file. + \param the user-supplied format. + \returns the type. The extension of the file directly maps to the + name of the format. +*/ +/**************************************************************************/ +int gk_csr_DetermineFormat(char *filename, int format) +{ + if (format != GK_CSR_FMT_AUTO) + return format; + + format = GK_CSR_FMT_CSR; + char *extension = gk_getextname(filename); + + if (!strcmp(extension, "csr")) + format = GK_CSR_FMT_CSR; + else if (!strcmp(extension, "ijv")) + format = GK_CSR_FMT_IJV; + else if (!strcmp(extension, "cluto")) + format = GK_CSR_FMT_CLUTO; + else if (!strcmp(extension, "metis")) + format = GK_CSR_FMT_METIS; + else if (!strcmp(extension, "binrow")) + format = GK_CSR_FMT_BINROW; + else if (!strcmp(extension, "bincol")) + format = GK_CSR_FMT_BINCOL; + else if (!strcmp(extension, "bijv")) + format = GK_CSR_FMT_BIJV; + + gk_free((void **)&extension, LTERM); + + return format; +} + + +/**************************************************************************/ +/*! Reads a CSR matrix from the supplied file and stores it the matrix's + forward structure. + \param filename is the file that stores the data. + \param format is either GK_CSR_FMT_METIS, GK_CSR_FMT_CLUTO, + GK_CSR_FMT_CSR, GK_CSR_FMT_BINROW, GK_CSR_FMT_BINCOL + specifying the type of the input format. + The GK_CSR_FMT_CSR does not contain a header + line, whereas the GK_CSR_FMT_BINROW is a binary format written + by gk_csr_Write() using the same format specifier. + \param readvals is either 1 or 0, indicating if the CSR file contains + values or it does not. It only applies when GK_CSR_FMT_CSR is + used. + \param numbering is either 1 or 0, indicating if the numbering of the + indices start from 1 or 0, respectively. If they start from 1, + they are automatically decreamented during input so that they + will start from 0. It only applies when GK_CSR_FMT_CSR is + used. + \returns the matrix that was read. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_Read(char *filename, int format, int readvals, int numbering) +{ + ssize_t i, k, l; + size_t nfields, nrows, ncols, nnz, fmt, ncon; + size_t lnlen; + ssize_t *rowptr; + int *rowind, *iinds, *jinds, ival; + float *rowval=NULL, *vals, fval; + int readsizes, readwgts; + char *line=NULL, *head, *tail, fmtstr[256]; + FILE *fpin; + gk_csr_t *mat=NULL; + + format = gk_csr_DetermineFormat(filename, format); + + if (!gk_fexists(filename)) + gk_errexit(SIGERR, "File %s does not exist!\n", filename); + + switch (format) { + case GK_CSR_FMT_BINROW: + mat = gk_csr_Create(); + + fpin = gk_fopen(filename, "rb", "gk_csr_Read: fpin"); + if (fread(&(mat->nrows), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the nrows from file %s!\n", filename); + if (fread(&(mat->ncols), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the ncols from file %s!\n", filename); + mat->rowptr = gk_zmalloc(mat->nrows+1, "gk_csr_Read: rowptr"); + if (fread(mat->rowptr, sizeof(ssize_t), mat->nrows+1, fpin) != mat->nrows+1) + gk_errexit(SIGERR, "Failed to read the rowptr from file %s!\n", filename); + mat->rowind = gk_imalloc(mat->rowptr[mat->nrows], "gk_csr_Read: rowind"); + if (fread(mat->rowind, sizeof(int32_t), mat->rowptr[mat->nrows], fpin) != mat->rowptr[mat->nrows]) + gk_errexit(SIGERR, "Failed to read the rowind from file %s!\n", filename); + if (readvals == 1) { + mat->rowval = gk_fmalloc(mat->rowptr[mat->nrows], "gk_csr_Read: rowval"); + if (fread(mat->rowval, sizeof(float), mat->rowptr[mat->nrows], fpin) != mat->rowptr[mat->nrows]) + gk_errexit(SIGERR, "Failed to read the rowval from file %s!\n", filename); + } + + gk_fclose(fpin); + return mat; + + break; + + case GK_CSR_FMT_BINCOL: + mat = gk_csr_Create(); + + fpin = gk_fopen(filename, "rb", "gk_csr_Read: fpin"); + if (fread(&(mat->nrows), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the nrows from file %s!\n", filename); + if (fread(&(mat->ncols), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the ncols from file %s!\n", filename); + mat->colptr = gk_zmalloc(mat->ncols+1, "gk_csr_Read: colptr"); + if (fread(mat->colptr, sizeof(ssize_t), mat->ncols+1, fpin) != mat->ncols+1) + gk_errexit(SIGERR, "Failed to read the colptr from file %s!\n", filename); + mat->colind = gk_imalloc(mat->colptr[mat->ncols], "gk_csr_Read: colind"); + if (fread(mat->colind, sizeof(int32_t), mat->colptr[mat->ncols], fpin) != mat->colptr[mat->ncols]) + gk_errexit(SIGERR, "Failed to read the colind from file %s!\n", filename); + if (readvals) { + mat->colval = gk_fmalloc(mat->colptr[mat->ncols], "gk_csr_Read: colval"); + if (fread(mat->colval, sizeof(float), mat->colptr[mat->ncols], fpin) != mat->colptr[mat->ncols]) + gk_errexit(SIGERR, "Failed to read the colval from file %s!\n", filename); + } + + gk_fclose(fpin); + return mat; + + break; + + + case GK_CSR_FMT_IJV: + gk_getfilestats(filename, &nrows, &nnz, NULL, NULL); + + if (readvals == 1 && 3*nrows != nnz) + gk_errexit(SIGERR, "Error: The number of numbers (%zd %d) in the input file is not a multiple of 3.\n", nnz, readvals); + if (readvals == 0 && 2*nrows != nnz) + gk_errexit(SIGERR, "Error: The number of numbers (%zd %d) in the input file is not a multiple of 2.\n", nnz, readvals); + + nnz = nrows; + numbering = (numbering ? - 1 : 0); + + /* read the data into three arrays */ + iinds = gk_i32malloc(nnz, "iinds"); + jinds = gk_i32malloc(nnz, "jinds"); + vals = (readvals ? gk_fmalloc(nnz, "vals") : NULL); + + fpin = gk_fopen(filename, "r", "gk_csr_Read: fpin"); + for (nrows=0, ncols=0, i=0; i<nnz; i++) { + if (readvals) { + if (fscanf(fpin, "%d %d %f", &iinds[i], &jinds[i], &vals[i]) != 3) + gk_errexit(SIGERR, "Error: Failed to read (i, j, val) for nnz: %zd.\n", i); + } + else { + if (fscanf(fpin, "%d %d", &iinds[i], &jinds[i]) != 2) + gk_errexit(SIGERR, "Error: Failed to read (i, j) value for nnz: %zd.\n", i); + } + iinds[i] += numbering; + jinds[i] += numbering; + + if (nrows < iinds[i]) + nrows = iinds[i]; + if (ncols < jinds[i]) + ncols = jinds[i]; + } + nrows++; + ncols++; + gk_fclose(fpin); + + /* convert (i, j, v) into a CSR matrix */ + mat = gk_csr_Create(); + mat->nrows = nrows; + mat->ncols = ncols; + rowptr = mat->rowptr = gk_zsmalloc(nrows+1, 0, "rowptr"); + rowind = mat->rowind = gk_i32malloc(nnz, "rowind"); + if (readvals) + rowval = mat->rowval = gk_fmalloc(nnz, "rowval"); + + for (i=0; i<nnz; i++) + rowptr[iinds[i]]++; + MAKECSR(i, nrows, rowptr); + + for (i=0; i<nnz; i++) { + rowind[rowptr[iinds[i]]] = jinds[i]; + if (readvals) + rowval[rowptr[iinds[i]]] = vals[i]; + rowptr[iinds[i]]++; + } + SHIFTCSR(i, nrows, rowptr); + + gk_free((void **)&iinds, &jinds, &vals, LTERM); + + return mat; + + break; + + case GK_CSR_FMT_BIJV: + mat = gk_csr_Create(); + + fpin = gk_fopen(filename, "rb", "gk_csr_Read: fpin"); + + if (fread(&(mat->nrows), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the nrows from file %s!\n", filename); + if (fread(&(mat->ncols), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the ncols from file %s!\n", filename); + if (fread(&nnz, sizeof(size_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the nnz from file %s!\n", filename); + if (fread(&readvals, sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read the readvals from file %s!\n", filename); + + /* read the data into three arrays */ + iinds = gk_i32malloc(nnz, "iinds"); + jinds = gk_i32malloc(nnz, "jinds"); + vals = (readvals ? gk_fmalloc(nnz, "vals") : NULL); + + for (i=0; i<nnz; i++) { + if (fread(&(iinds[i]), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read iinds[i] from file %s!\n", filename); + if (fread(&(jinds[i]), sizeof(int32_t), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read jinds[i] from file %s!\n", filename); + if (readvals) { + if (fread(&(vals[i]), sizeof(float), 1, fpin) != 1) + gk_errexit(SIGERR, "Failed to read vals[i] from file %s!\n", filename); + } + //printf("%d %d\n", iinds[i], jinds[i]); + } + gk_fclose(fpin); + + /* convert (i, j, v) into a CSR matrix */ + rowptr = mat->rowptr = gk_zsmalloc(mat->nrows+1, 0, "rowptr"); + rowind = mat->rowind = gk_i32malloc(nnz, "rowind"); + if (readvals) + rowval = mat->rowval = gk_fmalloc(nnz, "rowval"); + + for (i=0; i<nnz; i++) + rowptr[iinds[i]]++; + MAKECSR(i, mat->nrows, rowptr); + + for (i=0; i<nnz; i++) { + rowind[rowptr[iinds[i]]] = jinds[i]; + if (readvals) + rowval[rowptr[iinds[i]]] = vals[i]; + rowptr[iinds[i]]++; + } + SHIFTCSR(i, mat->nrows, rowptr); + + gk_free((void **)&iinds, &jinds, &vals, LTERM); + + return mat; + + break; + + + /* the following are handled by a common input code, that comes after the switch */ + + case GK_CSR_FMT_CLUTO: + fpin = gk_fopen(filename, "r", "gk_csr_Read: fpin"); + do { + if (gk_getline(&line, &lnlen, fpin) <= 0) + gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename); + } while (line[0] == '%'); + + if (sscanf(line, "%zu %zu %zu", &nrows, &ncols, &nnz) != 3) + gk_errexit(SIGERR, "Header line must contain 3 integers.\n"); + + readsizes = 0; + readwgts = 0; + readvals = 1; + numbering = 1; + + break; + + case GK_CSR_FMT_METIS: + fpin = gk_fopen(filename, "r", "gk_csr_Read: fpin"); + do { + if (gk_getline(&line, &lnlen, fpin) <= 0) + gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename); + } while (line[0] == '%'); + + fmt = ncon = 0; + nfields = sscanf(line, "%zu %zu %zu %zu", &nrows, &nnz, &fmt, &ncon); + if (nfields < 2) + gk_errexit(SIGERR, "Header line must contain at least 2 integers (#vtxs and #edges).\n"); + + ncols = nrows; + nnz *= 2; + + if (fmt > 111) + gk_errexit(SIGERR, "Cannot read this type of file format [fmt=%zu]!\n", fmt); + + sprintf(fmtstr, "%03zu", fmt%1000); + readsizes = (fmtstr[0] == '1'); + readwgts = (fmtstr[1] == '1'); + readvals = (fmtstr[2] == '1'); + numbering = 1; + ncon = (ncon == 0 ? 1 : ncon); + + break; + + case GK_CSR_FMT_CSR: + readsizes = 0; + readwgts = 0; + + gk_getfilestats(filename, &nrows, &nnz, NULL, NULL); + + if (readvals == 1 && nnz%2 == 1) + gk_errexit(SIGERR, "Error: The number of numbers (%zd %d) in the input file is not even.\n", nnz, readvals); + if (readvals == 1) + nnz = nnz/2; + fpin = gk_fopen(filename, "r", "gk_csr_Read: fpin"); + + break; + + default: + gk_errexit(SIGERR, "Unknown csr format.\n"); + return NULL; + } + + mat = gk_csr_Create(); + + mat->nrows = nrows; + + rowptr = mat->rowptr = gk_zmalloc(nrows+1, "gk_csr_Read: rowptr"); + rowind = mat->rowind = gk_imalloc(nnz, "gk_csr_Read: rowind"); + if (readvals != 2) + rowval = mat->rowval = gk_fsmalloc(nnz, 1.0, "gk_csr_Read: rowval"); + + if (readsizes) + mat->rsizes = gk_fsmalloc(nrows, 0.0, "gk_csr_Read: rsizes"); + + if (readwgts) + mat->rwgts = gk_fsmalloc(nrows*ncon, 0.0, "gk_csr_Read: rwgts"); + + /*---------------------------------------------------------------------- + * Read the sparse matrix file + *---------------------------------------------------------------------*/ + numbering = (numbering ? -1 : 0); + for (ncols=0, rowptr[0]=0, k=0, i=0; i<nrows; i++) { + do { + if (gk_getline(&line, &lnlen, fpin) == -1) + gk_errexit(SIGERR, "Premature end of input file: file while reading row %d\n", i); + } while (line[0] == '%'); + + head = line; + tail = NULL; + + /* Read vertex sizes */ + if (readsizes) { +#ifdef __MSC__ + mat->rsizes[i] = (float)strtod(head, &tail); +#else + mat->rsizes[i] = strtof(head, &tail); +#endif + if (tail == head) + gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1); + if (mat->rsizes[i] < 0) + errexit("The size for vertex %zd must be >= 0\n", i+1); + head = tail; + } + + /* Read vertex weights */ + if (readwgts) { + for (l=0; l<ncon; l++) { +#ifdef __MSC__ + mat->rwgts[i*ncon+l] = (float)strtod(head, &tail); +#else + mat->rwgts[i*ncon+l] = strtof(head, &tail); +#endif + if (tail == head) + errexit("The line for vertex %zd does not have enough weights " + "for the %d constraints.\n", i+1, ncon); + if (mat->rwgts[i*ncon+l] < 0) + errexit("The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l); + head = tail; + } + } + + + /* Read the rest of the row */ + while (1) { + ival = (int)strtol(head, &tail, 0); + if (tail == head) + break; + head = tail; + + if ((rowind[k] = ival + numbering) < 0) + gk_errexit(SIGERR, "Error: Invalid column number %d at row %zd.\n", ival, i); + + ncols = gk_max(rowind[k], ncols); + + if (readvals == 1) { +#ifdef __MSC__ + fval = (float)strtod(head, &tail); +#else + fval = strtof(head, &tail); +#endif + if (tail == head) + gk_errexit(SIGERR, "Value could not be found for column! Row:%zd, NNZ:%zd\n", i, k); + head = tail; + + rowval[k] = fval; + } + k++; + } + rowptr[i+1] = k; + } + + if (format == GK_CSR_FMT_METIS) { + ASSERT(ncols+1 == mat->nrows); + mat->ncols = mat->nrows; + } + else { + mat->ncols = ncols+1; + } + + if (k != nnz) + gk_errexit(SIGERR, "gk_csr_Read: Something wrong with the number of nonzeros in " + "the input file. NNZ=%zd, ActualNNZ=%zd.\n", nnz, k); + + gk_fclose(fpin); + + gk_free((void **)&line, LTERM); + + return mat; +} + + +/**************************************************************************/ +/*! Writes the row-based structure of a matrix into a file. + \param mat is the matrix to be written, + \param filename is the name of the output file. + \param format is one of: GK_CSR_FMT_CLUTO, GK_CSR_FMT_CSR, + GK_CSR_FMT_BINROW, GK_CSR_FMT_BINCOL, GK_CSR_FMT_BIJV. + \param writevals is either 1 or 0 indicating if the values will be + written or not. This is only applicable when GK_CSR_FMT_CSR + is used. + \param numbering is either 1 or 0 indicating if the internal 0-based + numbering will be shifted by one or not during output. This + is only applicable when GK_CSR_FMT_CSR is used. +*/ +/**************************************************************************/ +void gk_csr_Write(gk_csr_t *mat, char *filename, int format, int writevals, int numbering) +{ + ssize_t i, j; + int32_t edge[2]; + FILE *fpout; + + format = gk_csr_DetermineFormat(filename, format); + + switch (format) { + case GK_CSR_FMT_METIS: + if (mat->nrows != mat->ncols || mat->rowptr[mat->nrows]%2 == 1) + gk_errexit(SIGERR, "METIS output format requires a square symmetric matrix.\n"); + + if (filename) + fpout = gk_fopen(filename, "w", "gk_csr_Write: fpout"); + else + fpout = stdout; + + fprintf(fpout, "%d %zd\n", mat->nrows, mat->rowptr[mat->nrows]/2); + for (i=0; i<mat->nrows; i++) { + for (j=mat->rowptr[i]; j<mat->rowptr[i+1]; j++) + fprintf(fpout, " %d", mat->rowind[j]+1); + fprintf(fpout, "\n"); + } + if (filename) + gk_fclose(fpout); + break; + + case GK_CSR_FMT_BINROW: + if (filename == NULL) + gk_errexit(SIGERR, "The filename parameter cannot be NULL.\n"); + fpout = gk_fopen(filename, "wb", "gk_csr_Write: fpout"); + + fwrite(&(mat->nrows), sizeof(int32_t), 1, fpout); + fwrite(&(mat->ncols), sizeof(int32_t), 1, fpout); + fwrite(mat->rowptr, sizeof(ssize_t), mat->nrows+1, fpout); + fwrite(mat->rowind, sizeof(int32_t), mat->rowptr[mat->nrows], fpout); + if (writevals) + fwrite(mat->rowval, sizeof(float), mat->rowptr[mat->nrows], fpout); + + gk_fclose(fpout); + return; + + break; + + case GK_CSR_FMT_BINCOL: + if (filename == NULL) + gk_errexit(SIGERR, "The filename parameter cannot be NULL.\n"); + fpout = gk_fopen(filename, "wb", "gk_csr_Write: fpout"); + + fwrite(&(mat->nrows), sizeof(int32_t), 1, fpout); + fwrite(&(mat->ncols), sizeof(int32_t), 1, fpout); + fwrite(mat->colptr, sizeof(ssize_t), mat->ncols+1, fpout); + fwrite(mat->colind, sizeof(int32_t), mat->colptr[mat->ncols], fpout); + if (writevals) + fwrite(mat->colval, sizeof(float), mat->colptr[mat->ncols], fpout); + + gk_fclose(fpout); + return; + + break; + + case GK_CSR_FMT_IJV: + if (filename == NULL) + gk_errexit(SIGERR, "The filename parameter cannot be NULL.\n"); + fpout = gk_fopen(filename, "w", "gk_csr_Write: fpout"); + + numbering = (numbering ? 1 : 0); + for (i=0; i<mat->nrows; i++) { + for (j=mat->rowptr[i]; j<mat->rowptr[i+1]; j++) { + if (writevals) + fprintf(fpout, "%zd %d %.8f\n", i+numbering, mat->rowind[j]+numbering, mat->rowval[j]); + else + fprintf(fpout, "%zd %d\n", i+numbering, mat->rowind[j]+numbering); + } + } + + gk_fclose(fpout); + return; + + break; + + case GK_CSR_FMT_BIJV: + if (filename == NULL) + gk_errexit(SIGERR, "The filename parameter cannot be NULL.\n"); + fpout = gk_fopen(filename, "wb", "gk_csr_Write: fpout"); + + fwrite(&(mat->nrows), sizeof(int32_t), 1, fpout); + fwrite(&(mat->ncols), sizeof(int32_t), 1, fpout); + fwrite(&(mat->rowptr[mat->nrows]), sizeof(size_t), 1, fpout); + fwrite(&writevals, sizeof(int32_t), 1, fpout); + + for (i=0; i<mat->nrows; i++) { + edge[0] = i; + for (j=mat->rowptr[i]; j<mat->rowptr[i+1]; j++) { + edge[1] = mat->rowind[j]; + fwrite(edge, sizeof(int32_t), 2, fpout); + if (writevals) + fwrite(&(mat->rowval[j]), sizeof(float), 1, fpout); + } + } + + gk_fclose(fpout); + return; + + break; + + default: + if (filename) + fpout = gk_fopen(filename, "w", "gk_csr_Write: fpout"); + else + fpout = stdout; + + if (format == GK_CSR_FMT_CLUTO) { + fprintf(fpout, "%d %d %zd\n", mat->nrows, mat->ncols, mat->rowptr[mat->nrows]); + writevals = 1; + numbering = 1; + } + + for (i=0; i<mat->nrows; i++) { + for (j=mat->rowptr[i]; j<mat->rowptr[i+1]; j++) { + fprintf(fpout, " %d", mat->rowind[j]+(numbering ? 1 : 0)); + if (writevals) + fprintf(fpout, " %f", mat->rowval[j]); + } + fprintf(fpout, "\n"); + } + if (filename) + gk_fclose(fpout); + } +} + + +/*************************************************************************/ +/*! Prunes certain rows/columns of the matrix. The prunning takes place + by analyzing the row structure of the matrix. The prunning takes place + by removing rows/columns but it does not affect the numbering of the + remaining rows/columns. + + \param mat the matrix to be prunned, + \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) + of the matrix will be prunned, + \param minf is the minimum number of rows (columns) that a column (row) must + be present in order to be kept, + \param maxf is the maximum number of rows (columns) that a column (row) must + be present at in order to be kept. + \returns the prunned matrix consisting only of its row-based structure. + The input matrix is not modified. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_Prune(gk_csr_t *mat, int what, int minf, int maxf) +{ + ssize_t i, j, nnz; + int nrows, ncols; + ssize_t *rowptr, *nrowptr; + int *rowind, *nrowind, *collen; + float *rowval, *nrowval; + gk_csr_t *nmat; + + nmat = gk_csr_Create(); + + nrows = nmat->nrows = mat->nrows; + ncols = nmat->ncols = mat->ncols; + + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + + nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_Prune: nrowptr"); + nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_Prune: nrowind"); + nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_Prune: nrowval"); + + + switch (what) { + case GK_CSR_COL: + collen = gk_ismalloc(ncols, 0, "gk_csr_Prune: collen"); + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + ASSERT(rowind[j] < ncols); + collen[rowind[j]]++; + } + } + for (i=0; i<ncols; i++) + collen[i] = (collen[i] >= minf && collen[i] <= maxf ? 1 : 0); + + nrowptr[0] = 0; + for (nnz=0, i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (collen[rowind[j]]) { + nrowind[nnz] = rowind[j]; + nrowval[nnz] = rowval[j]; + nnz++; + } + } + nrowptr[i+1] = nnz; + } + gk_free((void **)&collen, LTERM); + break; + + case GK_CSR_ROW: + nrowptr[0] = 0; + for (nnz=0, i=0; i<nrows; i++) { + if (rowptr[i+1]-rowptr[i] >= minf && rowptr[i+1]-rowptr[i] <= maxf) { + for (j=rowptr[i]; j<rowptr[i+1]; j++, nnz++) { + nrowind[nnz] = rowind[j]; + nrowval[nnz] = rowval[j]; + } + } + nrowptr[i+1] = nnz; + } + break; + + default: + gk_csr_Free(&nmat); + gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); + return NULL; + } + + return nmat; +} + + +/*************************************************************************/ +/*! Eliminates certain entries from the rows/columns of the matrix. The + filtering takes place by keeping only the highest weight entries whose + sum accounts for a certain fraction of the overall weight of the + row/column. + + \param mat the matrix to be prunned, + \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) + of the matrix will be prunned, + \param norm indicates the norm that will be used to aggregate the weights + and possible values are 1 or 2, + \param fraction is the fraction of the overall norm that will be retained + by the kept entries. + \returns the filtered matrix consisting only of its row-based structure. + The input matrix is not modified. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_LowFilter(gk_csr_t *mat, int what, int norm, float fraction) +{ + ssize_t i, j, nnz; + int nrows, ncols, ncand, maxlen=0; + ssize_t *rowptr, *colptr, *nrowptr; + int *rowind, *colind, *nrowind; + float *rowval, *colval, *nrowval, rsum, tsum; + gk_csr_t *nmat; + gk_fkv_t *cand; + + nmat = gk_csr_Create(); + + nrows = nmat->nrows = mat->nrows; + ncols = nmat->ncols = mat->ncols; + + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + colptr = mat->colptr; + colind = mat->colind; + colval = mat->colval; + + nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_LowFilter: nrowptr"); + nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_LowFilter: nrowind"); + nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_LowFilter: nrowval"); + + + switch (what) { + case GK_CSR_COL: + if (mat->colptr == NULL) + gk_errexit(SIGERR, "Cannot filter columns when column-based structure has not been created.\n"); + + gk_zcopy(nrows+1, rowptr, nrowptr); + + for (i=0; i<ncols; i++) + maxlen = gk_max(maxlen, colptr[i+1]-colptr[i]); + + #pragma omp parallel private(i, j, ncand, rsum, tsum, cand) + { + cand = gk_fkvmalloc(maxlen, "gk_csr_LowFilter: cand"); + + #pragma omp for schedule(static) + for (i=0; i<ncols; i++) { + for (tsum=0.0, ncand=0, j=colptr[i]; j<colptr[i+1]; j++, ncand++) { + cand[ncand].val = colind[j]; + cand[ncand].key = colval[j]; + tsum += (norm == 1 ? colval[j] : colval[j]*colval[j]); + } + gk_fkvsortd(ncand, cand); + + for (rsum=0.0, j=0; j<ncand && rsum<=fraction*tsum; j++) { + rsum += (norm == 1 ? cand[j].key : cand[j].key*cand[j].key); + nrowind[nrowptr[cand[j].val]] = i; + nrowval[nrowptr[cand[j].val]] = cand[j].key; + nrowptr[cand[j].val]++; + } + } + + gk_free((void **)&cand, LTERM); + } + + /* compact the nrowind/nrowval */ + for (nnz=0, i=0; i<nrows; i++) { + for (j=rowptr[i]; j<nrowptr[i]; j++, nnz++) { + nrowind[nnz] = nrowind[j]; + nrowval[nnz] = nrowval[j]; + } + nrowptr[i] = nnz; + } + SHIFTCSR(i, nrows, nrowptr); + + break; + + case GK_CSR_ROW: + if (mat->rowptr == NULL) + gk_errexit(SIGERR, "Cannot filter rows when row-based structure has not been created.\n"); + + for (i=0; i<nrows; i++) + maxlen = gk_max(maxlen, rowptr[i+1]-rowptr[i]); + + #pragma omp parallel private(i, j, ncand, rsum, tsum, cand) + { + cand = gk_fkvmalloc(maxlen, "gk_csr_LowFilter: cand"); + + #pragma omp for schedule(static) + for (i=0; i<nrows; i++) { + for (tsum=0.0, ncand=0, j=rowptr[i]; j<rowptr[i+1]; j++, ncand++) { + cand[ncand].val = rowind[j]; + cand[ncand].key = rowval[j]; + tsum += (norm == 1 ? rowval[j] : rowval[j]*rowval[j]); + } + gk_fkvsortd(ncand, cand); + + for (rsum=0.0, j=0; j<ncand && rsum<=fraction*tsum; j++) { + rsum += (norm == 1 ? cand[j].key : cand[j].key*cand[j].key); + nrowind[rowptr[i]+j] = cand[j].val; + nrowval[rowptr[i]+j] = cand[j].key; + } + nrowptr[i+1] = rowptr[i]+j; + } + + gk_free((void **)&cand, LTERM); + } + + /* compact nrowind/nrowval */ + nrowptr[0] = nnz = 0; + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<nrowptr[i+1]; j++, nnz++) { + nrowind[nnz] = nrowind[j]; + nrowval[nnz] = nrowval[j]; + } + nrowptr[i+1] = nnz; + } + + break; + + default: + gk_csr_Free(&nmat); + gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); + return NULL; + } + + return nmat; +} + + +/*************************************************************************/ +/*! Eliminates certain entries from the rows/columns of the matrix. The + filtering takes place by keeping only the highest weight top-K entries + along each row/column and those entries whose weight is greater than + a specified value. + + \param mat the matrix to be prunned, + \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) + of the matrix will be prunned, + \param topk is the number of the highest weight entries to keep. + \param keepval is the weight of a term above which will be kept. This + is used to select additional terms past the first topk. + \returns the filtered matrix consisting only of its row-based structure. + The input matrix is not modified. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_TopKPlusFilter(gk_csr_t *mat, int what, int topk, float keepval) +{ + ssize_t i, j, k, nnz; + int nrows, ncols, ncand; + ssize_t *rowptr, *colptr, *nrowptr; + int *rowind, *colind, *nrowind; + float *rowval, *colval, *nrowval; + gk_csr_t *nmat; + gk_fkv_t *cand; + + nmat = gk_csr_Create(); + + nrows = nmat->nrows = mat->nrows; + ncols = nmat->ncols = mat->ncols; + + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + colptr = mat->colptr; + colind = mat->colind; + colval = mat->colval; + + nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_LowFilter: nrowptr"); + nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_LowFilter: nrowind"); + nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_LowFilter: nrowval"); + + + switch (what) { + case GK_CSR_COL: + if (mat->colptr == NULL) + gk_errexit(SIGERR, "Cannot filter columns when column-based structure has not been created.\n"); + + cand = gk_fkvmalloc(nrows, "gk_csr_LowFilter: cand"); + + gk_zcopy(nrows+1, rowptr, nrowptr); + for (i=0; i<ncols; i++) { + for (ncand=0, j=colptr[i]; j<colptr[i+1]; j++, ncand++) { + cand[ncand].val = colind[j]; + cand[ncand].key = colval[j]; + } + gk_fkvsortd(ncand, cand); + + k = gk_min(topk, ncand); + for (j=0; j<k; j++) { + nrowind[nrowptr[cand[j].val]] = i; + nrowval[nrowptr[cand[j].val]] = cand[j].key; + nrowptr[cand[j].val]++; + } + for (; j<ncand; j++) { + if (cand[j].key < keepval) + break; + + nrowind[nrowptr[cand[j].val]] = i; + nrowval[nrowptr[cand[j].val]] = cand[j].key; + nrowptr[cand[j].val]++; + } + } + + /* compact the nrowind/nrowval */ + for (nnz=0, i=0; i<nrows; i++) { + for (j=rowptr[i]; j<nrowptr[i]; j++, nnz++) { + nrowind[nnz] = nrowind[j]; + nrowval[nnz] = nrowval[j]; + } + nrowptr[i] = nnz; + } + SHIFTCSR(i, nrows, nrowptr); + + gk_free((void **)&cand, LTERM); + break; + + case GK_CSR_ROW: + if (mat->rowptr == NULL) + gk_errexit(SIGERR, "Cannot filter rows when row-based structure has not been created.\n"); + + cand = gk_fkvmalloc(ncols, "gk_csr_LowFilter: cand"); + + nrowptr[0] = 0; + for (nnz=0, i=0; i<nrows; i++) { + for (ncand=0, j=rowptr[i]; j<rowptr[i+1]; j++, ncand++) { + cand[ncand].val = rowind[j]; + cand[ncand].key = rowval[j]; + } + gk_fkvsortd(ncand, cand); + + k = gk_min(topk, ncand); + for (j=0; j<k; j++, nnz++) { + nrowind[nnz] = cand[j].val; + nrowval[nnz] = cand[j].key; + } + for (; j<ncand; j++, nnz++) { + if (cand[j].key < keepval) + break; + + nrowind[nnz] = cand[j].val; + nrowval[nnz] = cand[j].key; + } + nrowptr[i+1] = nnz; + } + + gk_free((void **)&cand, LTERM); + break; + + default: + gk_csr_Free(&nmat); + gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); + return NULL; + } + + return nmat; +} + + +/*************************************************************************/ +/*! Eliminates certain entries from the rows/columns of the matrix. The + filtering takes place by keeping only the terms whose contribution to + the total length of the document is greater than a user-splied multiple + over the average. + + This routine assumes that the vectors are normalized to be unit length. + + \param mat the matrix to be prunned, + \param what indicates if the rows (GK_CSR_ROW) or the columns (GK_CSR_COL) + of the matrix will be prunned, + \param zscore is the multiplicative factor over the average contribution + to the length of the document. + \returns the filtered matrix consisting only of its row-based structure. + The input matrix is not modified. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_ZScoreFilter(gk_csr_t *mat, int what, float zscore) +{ + ssize_t i, j, nnz; + int nrows; + ssize_t *rowptr, *nrowptr; + int *rowind, *nrowind; + float *rowval, *nrowval, avgwgt; + gk_csr_t *nmat; + + nmat = gk_csr_Create(); + + nmat->nrows = mat->nrows; + nmat->ncols = mat->ncols; + + nrows = mat->nrows; + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + + nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_ZScoreFilter: nrowptr"); + nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_ZScoreFilter: nrowind"); + nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_ZScoreFilter: nrowval"); + + + switch (what) { + case GK_CSR_COL: + gk_errexit(SIGERR, "This has not been implemented yet.\n"); + break; + + case GK_CSR_ROW: + if (mat->rowptr == NULL) + gk_errexit(SIGERR, "Cannot filter rows when row-based structure has not been created.\n"); + + nrowptr[0] = 0; + for (nnz=0, i=0; i<nrows; i++) { + avgwgt = zscore/(rowptr[i+1]-rowptr[i]); + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (rowval[j] > avgwgt) { + nrowind[nnz] = rowind[j]; + nrowval[nnz] = rowval[j]; + nnz++; + } + } + nrowptr[i+1] = nnz; + } + break; + + default: + gk_csr_Free(&nmat); + gk_errexit(SIGERR, "Unknown prunning type of %d\n", what); + return NULL; + } + + return nmat; +} + + +/*************************************************************************/ +/*! Compacts the column-space of the matrix by removing empty columns. + As a result of the compaction, the column numbers are renumbered. + The compaction operation is done in place and only affects the row-based + representation of the matrix. + The new columns are ordered in decreasing frequency. + + \param mat the matrix whose empty columns will be removed. +*/ +/**************************************************************************/ +void gk_csr_CompactColumns(gk_csr_t *mat) +{ + ssize_t i; + int nrows, ncols, nncols; + ssize_t *rowptr; + int *rowind, *colmap; + gk_ikv_t *clens; + + nrows = mat->nrows; + ncols = mat->ncols; + rowptr = mat->rowptr; + rowind = mat->rowind; + + colmap = gk_imalloc(ncols, "gk_csr_CompactColumns: colmap"); + + clens = gk_ikvmalloc(ncols, "gk_csr_CompactColumns: clens"); + for (i=0; i<ncols; i++) { + clens[i].key = 0; + clens[i].val = i; + } + + for (i=0; i<rowptr[nrows]; i++) + clens[rowind[i]].key++; + gk_ikvsortd(ncols, clens); + + for (nncols=0, i=0; i<ncols; i++) { + if (clens[i].key > 0) + colmap[clens[i].val] = nncols++; + else + break; + } + + for (i=0; i<rowptr[nrows]; i++) + rowind[i] = colmap[rowind[i]]; + + mat->ncols = nncols; + + gk_free((void **)&colmap, &clens, LTERM); +} + + +/*************************************************************************/ +/*! Sorts the indices in increasing order + \param mat the matrix itself, + \param what is either GK_CSR_ROW or GK_CSR_COL indicating which set of + indices to sort. +*/ +/**************************************************************************/ +void gk_csr_SortIndices(gk_csr_t *mat, int what) +{ + int n, nn=0; + ssize_t *ptr; + int *ind; + float *val; + + switch (what) { + case GK_CSR_ROW: + if (!mat->rowptr) + gk_errexit(SIGERR, "Row-based view of the matrix does not exists.\n"); + + n = mat->nrows; + ptr = mat->rowptr; + ind = mat->rowind; + val = mat->rowval; + break; + + case GK_CSR_COL: + if (!mat->colptr) + gk_errexit(SIGERR, "Column-based view of the matrix does not exists.\n"); + + n = mat->ncols; + ptr = mat->colptr; + ind = mat->colind; + val = mat->colval; + break; + + default: + gk_errexit(SIGERR, "Invalid index type of %d.\n", what); + return; + } + + #pragma omp parallel if (n > 100) + { + ssize_t i, j, k; + gk_ikv_t *cand; + float *tval; + + #pragma omp single + for (i=0; i<n; i++) + nn = gk_max(nn, ptr[i+1]-ptr[i]); + + cand = gk_ikvmalloc(nn, "gk_csr_SortIndices: cand"); + tval = gk_fmalloc(nn, "gk_csr_SortIndices: tval"); + + #pragma omp for schedule(static) + for (i=0; i<n; i++) { + for (k=0, j=ptr[i]; j<ptr[i+1]; j++) { + if (j > ptr[i] && ind[j] < ind[j-1]) + k = 1; /* an inversion */ + cand[j-ptr[i]].val = j-ptr[i]; + cand[j-ptr[i]].key = ind[j]; + tval[j-ptr[i]] = val[j]; + } + if (k) { + gk_ikvsorti(ptr[i+1]-ptr[i], cand); + for (j=ptr[i]; j<ptr[i+1]; j++) { + ind[j] = cand[j-ptr[i]].key; + val[j] = tval[cand[j-ptr[i]].val]; + } + } + } + + gk_free((void **)&cand, &tval, LTERM); + } + +} + + +/*************************************************************************/ +/*! Creates a row/column index from the column/row data. + \param mat the matrix itself, + \param what is either GK_CSR_ROW or GK_CSR_COL indicating which index + will be created. +*/ +/**************************************************************************/ +void gk_csr_CreateIndex(gk_csr_t *mat, int what) +{ + /* 'f' stands for forward, 'r' stands for reverse */ + ssize_t i, j, k, nf, nr; + ssize_t *fptr, *rptr; + int *find, *rind; + float *fval, *rval; + + switch (what) { + case GK_CSR_COL: + nf = mat->nrows; + fptr = mat->rowptr; + find = mat->rowind; + fval = mat->rowval; + + if (mat->colptr) gk_free((void **)&mat->colptr, LTERM); + if (mat->colind) gk_free((void **)&mat->colind, LTERM); + if (mat->colval) gk_free((void **)&mat->colval, LTERM); + + nr = mat->ncols; + rptr = mat->colptr = gk_zsmalloc(nr+1, 0, "gk_csr_CreateIndex: rptr"); + rind = mat->colind = gk_imalloc(fptr[nf], "gk_csr_CreateIndex: rind"); + rval = mat->colval = (fval ? gk_fmalloc(fptr[nf], "gk_csr_CreateIndex: rval") : NULL); + break; + case GK_CSR_ROW: + nf = mat->ncols; + fptr = mat->colptr; + find = mat->colind; + fval = mat->colval; + + if (mat->rowptr) gk_free((void **)&mat->rowptr, LTERM); + if (mat->rowind) gk_free((void **)&mat->rowind, LTERM); + if (mat->rowval) gk_free((void **)&mat->rowval, LTERM); + + nr = mat->nrows; + rptr = mat->rowptr = gk_zsmalloc(nr+1, 0, "gk_csr_CreateIndex: rptr"); + rind = mat->rowind = gk_imalloc(fptr[nf], "gk_csr_CreateIndex: rind"); + rval = mat->rowval = (fval ? gk_fmalloc(fptr[nf], "gk_csr_CreateIndex: rval") : NULL); + break; + default: + gk_errexit(SIGERR, "Invalid index type of %d.\n", what); + return; + } + + + for (i=0; i<nf; i++) { + for (j=fptr[i]; j<fptr[i+1]; j++) + rptr[find[j]]++; + } + MAKECSR(i, nr, rptr); + + if (rptr[nr] > 6*nr) { + for (i=0; i<nf; i++) { + for (j=fptr[i]; j<fptr[i+1]; j++) + rind[rptr[find[j]]++] = i; + } + SHIFTCSR(i, nr, rptr); + + if (fval) { + for (i=0; i<nf; i++) { + for (j=fptr[i]; j<fptr[i+1]; j++) + rval[rptr[find[j]]++] = fval[j]; + } + SHIFTCSR(i, nr, rptr); + } + } + else { + if (fval) { + for (i=0; i<nf; i++) { + for (j=fptr[i]; j<fptr[i+1]; j++) { + k = find[j]; + rind[rptr[k]] = i; + rval[rptr[k]++] = fval[j]; + } + } + } + else { + for (i=0; i<nf; i++) { + for (j=fptr[i]; j<fptr[i+1]; j++) + rind[rptr[find[j]]++] = i; + } + } + SHIFTCSR(i, nr, rptr); + } +} + + +/*************************************************************************/ +/*! Normalizes the rows/columns of the matrix to be unit + length. + \param mat the matrix itself, + \param what indicates what will be normalized and is obtained by + specifying GK_CSR_ROW, GK_CSR_COL, GK_CSR_ROW|GK_CSR_COL. + \param norm indicates what norm is to normalize to, 1: 1-norm, 2: 2-norm +*/ +/**************************************************************************/ +void gk_csr_Normalize(gk_csr_t *mat, int what, int norm) +{ + ssize_t i, j; + int n; + ssize_t *ptr; + float *val, sum; + + + if (what&GK_CSR_ROW && mat->rowval) { + n = mat->nrows; + ptr = mat->rowptr; + val = mat->rowval; + + #pragma omp parallel for if (ptr[n] > OMPMINOPS) private(j,sum) schedule(static) + for (i=0; i<n; i++) { + sum = 0.0; + if (norm == 1) { + for (j=ptr[i]; j<ptr[i+1]; j++) + sum += val[j]; /* assume val[j] > 0 */ + if (sum > 0) + sum = 1.0/sum; + } + else if (norm == 2) { + for (j=ptr[i]; j<ptr[i+1]; j++) + sum += val[j]*val[j]; + if (sum > 0) + sum = 1.0/sqrt(sum); + } + for (j=ptr[i]; j<ptr[i+1]; j++) + val[j] *= sum; + } + } + + if (what&GK_CSR_COL && mat->colval) { + n = mat->ncols; + ptr = mat->colptr; + val = mat->colval; + + #pragma omp parallel for if (ptr[n] > OMPMINOPS) private(j,sum) schedule(static) + for (i=0; i<n; i++) { + sum = 0.0; + if (norm == 1) { + for (j=ptr[i]; j<ptr[i+1]; j++) + sum += val[j]; /* assume val[j] > 0 */ + if (sum > 0) + sum = 1.0/sum; + } + else if (norm == 2) { + for (j=ptr[i]; j<ptr[i+1]; j++) + sum += val[j]*val[j]; + if (sum > 0) + sum = 1.0/sqrt(sum); + } + for (j=ptr[i]; j<ptr[i+1]; j++) + val[j] *= sum; + } + } + +} + + +/*************************************************************************/ +/*! Applies different row scaling methods. + \param mat the matrix itself, + \param type indicates the type of row scaling. Possible values are: + GK_CSR_MAXTF, GK_CSR_SQRT, GK_CSR_LOG, GK_CSR_IDF, GK_CSR_MAXTF2. +*/ +/**************************************************************************/ +void gk_csr_Scale(gk_csr_t *mat, int type) +{ + ssize_t i, j; + int nrows, ncols, nnzcols, bgfreq; + ssize_t *rowptr; + int *rowind, *collen; + float *rowval, *cscale, maxtf; + double logscale = 1.0/log(2.0); + + nrows = mat->nrows; + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + + switch (type) { + case GK_CSR_MAXTF: /* TF' = .5 + .5*TF/MAX(TF) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j, maxtf) schedule(static) + for (i=0; i<nrows; i++) { + maxtf = fabs(rowval[rowptr[i]]); + for (j=rowptr[i]; j<rowptr[i+1]; j++) + maxtf = (maxtf < fabs(rowval[j]) ? fabs(rowval[j]) : maxtf); + + for (j=rowptr[i]; j<rowptr[i+1]; j++) + rowval[j] = .5 + .5*rowval[j]/maxtf; + } + break; + + case GK_CSR_MAXTF2: /* TF' = .1 + .9*TF/MAX(TF) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j, maxtf) schedule(static) + for (i=0; i<nrows; i++) { + maxtf = fabs(rowval[rowptr[i]]); + for (j=rowptr[i]; j<rowptr[i+1]; j++) + maxtf = (maxtf < fabs(rowval[j]) ? fabs(rowval[j]) : maxtf); + + for (j=rowptr[i]; j<rowptr[i+1]; j++) + rowval[j] = .1 + .9*rowval[j]/maxtf; + } + break; + + case GK_CSR_SQRT: /* TF' = .1+SQRT(TF) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (rowval[j] != 0.0) + rowval[j] = .1+sign(rowval[j], sqrt(fabs(rowval[j]))); + } + } + + break; + + case GK_CSR_POW25: /* TF' = .1+POW(TF,.25) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (rowval[j] != 0.0) + rowval[j] = .1+sign(rowval[j], sqrt(sqrt(fabs(rowval[j])))); + } + } + break; + + case GK_CSR_POW65: /* TF' = .1+POW(TF,.65) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (rowval[j] != 0.0) + rowval[j] = .1+sign(rowval[j], powf(fabs(rowval[j]), .65)); + } + } + break; + + case GK_CSR_POW75: /* TF' = .1+POW(TF,.75) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (rowval[j] != 0.0) + rowval[j] = .1+sign(rowval[j], powf(fabs(rowval[j]), .75)); + } + } + break; + + case GK_CSR_POW85: /* TF' = .1+POW(TF,.85) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (rowval[j] != 0.0) + rowval[j] = .1+sign(rowval[j], powf(fabs(rowval[j]), .85)); + } + } + break; + + case GK_CSR_LOG: /* TF' = 1+log_2(TF) */ + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) schedule(static,32) + for (i=0; i<rowptr[nrows]; i++) { + if (rowval[i] != 0.0) + rowval[i] = 1+(rowval[i]>0.0 ? log(rowval[i]) : -log(-rowval[i]))*logscale; + } +#ifdef XXX + #pragma omp parallel for private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (rowval[j] != 0.0) + rowval[j] = 1+(rowval[j]>0.0 ? log(rowval[j]) : -log(-rowval[j]))*logscale; + //rowval[j] = 1+sign(rowval[j], log(fabs(rowval[j]))*logscale); + } + } +#endif + break; + + case GK_CSR_IDF: /* TF' = TF*IDF */ + ncols = mat->ncols; + cscale = gk_fmalloc(ncols, "gk_csr_Scale: cscale"); + collen = gk_ismalloc(ncols, 0, "gk_csr_Scale: collen"); + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + collen[rowind[j]]++; + } + + #pragma omp parallel for if (ncols > OMPMINOPS) schedule(static) + for (i=0; i<ncols; i++) + cscale[i] = (collen[i] > 0 ? log(1.0*nrows/collen[i]) : 0.0); + + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + rowval[j] *= cscale[rowind[j]]; + } + + gk_free((void **)&cscale, &collen, LTERM); + break; + + case GK_CSR_IDF2: /* TF' = TF*IDF */ + ncols = mat->ncols; + cscale = gk_fmalloc(ncols, "gk_csr_Scale: cscale"); + collen = gk_ismalloc(ncols, 0, "gk_csr_Scale: collen"); + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + collen[rowind[j]]++; + } + + nnzcols = 0; + #pragma omp parallel for if (ncols > OMPMINOPS) schedule(static) reduction(+:nnzcols) + for (i=0; i<ncols; i++) + nnzcols += (collen[i] > 0 ? 1 : 0); + + bgfreq = gk_max(10, (ssize_t)(.5*rowptr[nrows]/nnzcols)); + printf("nnz: %zd, nnzcols: %d, bgfreq: %d\n", rowptr[nrows], nnzcols, bgfreq); + + #pragma omp parallel for if (ncols > OMPMINOPS) schedule(static) + for (i=0; i<ncols; i++) + cscale[i] = (collen[i] > 0 ? log(1.0*(nrows+2*bgfreq)/(bgfreq+collen[i])) : 0.0); + + #pragma omp parallel for if (rowptr[nrows] > OMPMINOPS) private(j) schedule(static) + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + rowval[j] *= cscale[rowind[j]]; + } + + gk_free((void **)&cscale, &collen, LTERM); + break; + + default: + gk_errexit(SIGERR, "Unknown scaling type of %d\n", type); + } +} + + +/*************************************************************************/ +/*! Computes the sums of the rows/columns + \param mat the matrix itself, + \param what is either GK_CSR_ROW or GK_CSR_COL indicating which + sums to compute. +*/ +/**************************************************************************/ +void gk_csr_ComputeSums(gk_csr_t *mat, int what) +{ + ssize_t i; + int n; + ssize_t *ptr; + float *val, *sums; + + switch (what) { + case GK_CSR_ROW: + n = mat->nrows; + ptr = mat->rowptr; + val = mat->rowval; + + if (mat->rsums) + gk_free((void **)&mat->rsums, LTERM); + + sums = mat->rsums = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: sums"); + break; + case GK_CSR_COL: + n = mat->ncols; + ptr = mat->colptr; + val = mat->colval; + + if (mat->csums) + gk_free((void **)&mat->csums, LTERM); + + sums = mat->csums = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: sums"); + break; + default: + gk_errexit(SIGERR, "Invalid sum type of %d.\n", what); + return; + } + + if (val) { + #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) + for (i=0; i<n; i++) + sums[i] = gk_fsum(ptr[i+1]-ptr[i], val+ptr[i], 1); + } + else { + #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) + for (i=0; i<n; i++) + sums[i] = ptr[i+1]-ptr[i]; + } +} + + +/*************************************************************************/ +/*! Computes the norms of the rows/columns + + \param mat the matrix itself, + \param what is either GK_CSR_ROW or GK_CSR_COL indicating which + squared norms to compute. + + \note If the rowval/colval arrays are NULL, the matrix is assumed + to be binary and the norms are computed accordingly. +*/ +/**************************************************************************/ +void gk_csr_ComputeNorms(gk_csr_t *mat, int what) +{ + ssize_t i; + int n; + ssize_t *ptr; + float *val, *norms; + + switch (what) { + case GK_CSR_ROW: + n = mat->nrows; + ptr = mat->rowptr; + val = mat->rowval; + + if (mat->rnorms) gk_free((void **)&mat->rnorms, LTERM); + + norms = mat->rnorms = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: norms"); + break; + case GK_CSR_COL: + n = mat->ncols; + ptr = mat->colptr; + val = mat->colval; + + if (mat->cnorms) gk_free((void **)&mat->cnorms, LTERM); + + norms = mat->cnorms = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: norms"); + break; + default: + gk_errexit(SIGERR, "Invalid norm type of %d.\n", what); + return; + } + + if (val) { + #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) + for (i=0; i<n; i++) + norms[i] = sqrt(gk_fdot(ptr[i+1]-ptr[i], val+ptr[i], 1, val+ptr[i], 1)); + } + else { + #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) + for (i=0; i<n; i++) + norms[i] = sqrt(ptr[i+1]-ptr[i]); + } +} + + +/*************************************************************************/ +/*! Computes the squared of the norms of the rows/columns + + \param mat the matrix itself, + \param what is either GK_CSR_ROW or GK_CSR_COL indicating which + squared norms to compute. + + \note If the rowval/colval arrays are NULL, the matrix is assumed + to be binary and the norms are computed accordingly. +*/ +/**************************************************************************/ +void gk_csr_ComputeSquaredNorms(gk_csr_t *mat, int what) +{ + ssize_t i; + int n; + ssize_t *ptr; + float *val, *norms; + + switch (what) { + case GK_CSR_ROW: + n = mat->nrows; + ptr = mat->rowptr; + val = mat->rowval; + + if (mat->rnorms) gk_free((void **)&mat->rnorms, LTERM); + + norms = mat->rnorms = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: norms"); + break; + case GK_CSR_COL: + n = mat->ncols; + ptr = mat->colptr; + val = mat->colval; + + if (mat->cnorms) gk_free((void **)&mat->cnorms, LTERM); + + norms = mat->cnorms = gk_fsmalloc(n, 0, "gk_csr_ComputeSums: norms"); + break; + default: + gk_errexit(SIGERR, "Invalid norm type of %d.\n", what); + return; + } + + if (val) { + #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) + for (i=0; i<n; i++) + norms[i] = gk_fdot(ptr[i+1]-ptr[i], val+ptr[i], 1, val+ptr[i], 1); + } + else { + #pragma omp parallel for if (ptr[n] > OMPMINOPS) schedule(static) + for (i=0; i<n; i++) + norms[i] = ptr[i+1]-ptr[i]; + } +} + + +/*************************************************************************/ +/*! Returns a new matrix whose rows/columns are shuffled. + + \param mat the matrix to be shuffled, + \param what indicates if the rows (GK_CSR_ROW), columns (GK_CSR_COL), + or both (GK_CSR_ROWCOL) will be shuffled, + \param symmetric indicates if the same shuffling will be applied to + both rows and columns. This is valid with nrows==ncols and + GK_CSR_ROWCOL was specified. + \returns the shuffled matrix. + The input matrix is not modified. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_Shuffle(gk_csr_t *mat, int what, int symmetric) +{ + ssize_t i, j; + int nrows, ncols; + ssize_t *rowptr, *nrowptr; + int *rowind, *nrowind; + int *rperm, *cperm; + float *rowval, *nrowval; + gk_csr_t *nmat; + + if (what == GK_CSR_ROWCOL && symmetric && mat->nrows != mat->ncols) + gk_errexit(SIGERR, "The matrix is not square for a symmetric rowcol shuffling.\n"); + + nrows = mat->nrows; + ncols = mat->ncols; + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + + rperm = gk_imalloc(nrows, "gk_csr_Shuffle: rperm"); + cperm = gk_imalloc(ncols, "gk_csr_Shuffle: cperm"); + + switch (what) { + case GK_CSR_ROW: + gk_RandomPermute(nrows, rperm, 1); + for (i=0; i<20; i++) + gk_RandomPermute(nrows, rperm, 0); + + for (i=0; i<ncols; i++) + cperm[i] = i; + break; + + case GK_CSR_COL: + gk_RandomPermute(ncols, cperm, 1); + for (i=0; i<20; i++) + gk_RandomPermute(ncols, cperm, 0); + + for (i=0; i<nrows; i++) + rperm[i] = i; + break; + + case GK_CSR_ROWCOL: + gk_RandomPermute(nrows, rperm, 1); + for (i=0; i<20; i++) + gk_RandomPermute(nrows, rperm, 0); + + if (symmetric) + gk_icopy(nrows, rperm, cperm); + else { + gk_RandomPermute(ncols, cperm, 1); + for (i=0; i<20; i++) + gk_RandomPermute(ncols, cperm, 0); + } + break; + + default: + gk_free((void **)&rperm, &cperm, LTERM); + gk_errexit(SIGERR, "Unknown shuffling type of %d\n", what); + return NULL; + } + + nmat = gk_csr_Create(); + nmat->nrows = nrows; + nmat->ncols = ncols; + + nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_Shuffle: nrowptr"); + nrowind = nmat->rowind = gk_imalloc(rowptr[nrows], "gk_csr_Shuffle: nrowind"); + nrowval = nmat->rowval = (rowval ? gk_fmalloc(rowptr[nrows], "gk_csr_Shuffle: nrowval") : NULL) ; + + for (i=0; i<nrows; i++) + nrowptr[rperm[i]] = rowptr[i+1]-rowptr[i]; + MAKECSR(i, nrows, nrowptr); + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + nrowind[nrowptr[rperm[i]]] = cperm[rowind[j]]; + if (nrowval) + nrowval[nrowptr[rperm[i]]] = rowval[j]; + nrowptr[rperm[i]]++; + } + } + SHIFTCSR(i, nrows, nrowptr); + + gk_free((void **)&rperm, &cperm, LTERM); + + return nmat; + +} + + +/*************************************************************************/ +/*! Returns the transpose of the matrix. + + \param mat the matrix to be transposed, + \returns the transposed matrix. + The input matrix is not modified. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_Transpose(gk_csr_t *mat) +{ + int nrows, ncols; + ssize_t *colptr; + int32_t *colind; + float *colval; + gk_csr_t *nmat; + + colptr = mat->colptr; + colind = mat->colind; + colval = mat->colval; + + mat->colptr = NULL; + mat->colind = NULL; + mat->colval = NULL; + + gk_csr_CreateIndex(mat, GK_CSR_COL); + + nmat = gk_csr_Create(); + nmat->nrows = mat->ncols; + nmat->ncols = mat->nrows; + nmat->rowptr = mat->colptr; + nmat->rowind = mat->colind; + nmat->rowval = mat->colval; + + mat->colptr = colptr; + mat->colind = colind; + mat->colval = colval; + + return nmat; + +} + + +/*************************************************************************/ +/*! Computes the similarity between two rows/columns + + \param mat the matrix itself. The routine assumes that the indices + are sorted in increasing order. + \param i1 is the first row/column, + \param i2 is the second row/column, + \param what is either GK_CSR_ROW or GK_CSR_COL indicating the type of + objects between the similarity will be computed, + \param simtype is the type of similarity and is one of GK_CSR_COS, + GK_CSR_JAC, GK_CSR_MIN, GK_CSR_AMIN + \returns the similarity between the two rows/columns. +*/ +/**************************************************************************/ +float gk_csr_ComputeSimilarity(gk_csr_t *mat, int i1, int i2, int what, + int simtype) +{ + int nind1, nind2; + int *ind1, *ind2; + float *val1, *val2, stat1, stat2, sim; + + switch (what) { + case GK_CSR_ROW: + if (!mat->rowptr) + gk_errexit(SIGERR, "Row-based view of the matrix does not exists.\n"); + nind1 = mat->rowptr[i1+1]-mat->rowptr[i1]; + nind2 = mat->rowptr[i2+1]-mat->rowptr[i2]; + ind1 = mat->rowind + mat->rowptr[i1]; + ind2 = mat->rowind + mat->rowptr[i2]; + val1 = mat->rowval + mat->rowptr[i1]; + val2 = mat->rowval + mat->rowptr[i2]; + break; + + case GK_CSR_COL: + if (!mat->colptr) + gk_errexit(SIGERR, "Column-based view of the matrix does not exists.\n"); + nind1 = mat->colptr[i1+1]-mat->colptr[i1]; + nind2 = mat->colptr[i2+1]-mat->colptr[i2]; + ind1 = mat->colind + mat->colptr[i1]; + ind2 = mat->colind + mat->colptr[i2]; + val1 = mat->colval + mat->colptr[i1]; + val2 = mat->colval + mat->colptr[i2]; + break; + + default: + gk_errexit(SIGERR, "Invalid index type of %d.\n", what); + return 0.0; + } + + + switch (simtype) { + case GK_CSR_COS: + case GK_CSR_JAC: + sim = stat1 = stat2 = 0.0; + i1 = i2 = 0; + while (i1<nind1 && i2<nind2) { + if (i1 == nind1) { + stat2 += val2[i2]*val2[i2]; + i2++; + } + else if (i2 == nind2) { + stat1 += val1[i1]*val1[i1]; + i1++; + } + else if (ind1[i1] < ind2[i2]) { + stat1 += val1[i1]*val1[i1]; + i1++; + } + else if (ind1[i1] > ind2[i2]) { + stat2 += val2[i2]*val2[i2]; + i2++; + } + else { + sim += val1[i1]*val2[i2]; + stat1 += val1[i1]*val1[i1]; + stat2 += val2[i2]*val2[i2]; + i1++; + i2++; + } + } + if (simtype == GK_CSR_COS) + sim = (stat1*stat2 > 0.0 ? sim/sqrt(stat1*stat2) : 0.0); + else + sim = (stat1+stat2-sim > 0.0 ? sim/(stat1+stat2-sim) : 0.0); + break; + + case GK_CSR_MIN: + sim = stat1 = stat2 = 0.0; + i1 = i2 = 0; + while (i1<nind1 && i2<nind2) { + if (i1 == nind1) { + stat2 += val2[i2]; + i2++; + } + else if (i2 == nind2) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] < ind2[i2]) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] > ind2[i2]) { + stat2 += val2[i2]; + i2++; + } + else { + sim += gk_min(val1[i1],val2[i2]); + stat1 += val1[i1]; + stat2 += val2[i2]; + i1++; + i2++; + } + } + sim = (stat1+stat2-sim > 0.0 ? sim/(stat1+stat2-sim) : 0.0); + + break; + + case GK_CSR_AMIN: + sim = stat1 = stat2 = 0.0; + i1 = i2 = 0; + while (i1<nind1 && i2<nind2) { + if (i1 == nind1) { + stat2 += val2[i2]; + i2++; + } + else if (i2 == nind2) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] < ind2[i2]) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] > ind2[i2]) { + stat2 += val2[i2]; + i2++; + } + else { + sim += gk_min(val1[i1],val2[i2]); + stat1 += val1[i1]; + stat2 += val2[i2]; + i1++; + i2++; + } + } + sim = (stat1 > 0.0 ? sim/stat1 : 0.0); + + break; + + default: + gk_errexit(SIGERR, "Unknown similarity measure %d\n", simtype); + return -1; + } + + return sim; + +} + + +/*************************************************************************/ +/*! Computes the similarity between two rows/columns + + \param mat_a the first matrix. The routine assumes that the indices + are sorted in increasing order. + \param mat_b the second matrix. The routine assumes that the indices + are sorted in increasing order. + \param i1 is the row/column from the first matrix (mat_a), + \param i2 is the row/column from the second matrix (mat_b), + \param what is either GK_CSR_ROW or GK_CSR_COL indicating the type of + objects between the similarity will be computed, + \param simtype is the type of similarity and is one of GK_CSR_COS, + GK_CSR_JAC, GK_CSR_MIN, GK_CSR_AMIN + \returns the similarity between the two rows/columns. +*/ +/**************************************************************************/ +float gk_csr_ComputePairSimilarity(gk_csr_t *mat_a, gk_csr_t *mat_b, + int i1, int i2, int what, int simtype) +{ + int nind1, nind2; + int *ind1, *ind2; + float *val1, *val2, stat1, stat2, sim; + + switch (what) { + case GK_CSR_ROW: + if (!mat_a->rowptr || !mat_b->rowptr) + gk_errexit(SIGERR, "Row-based view of the matrix does not exists.\n"); + nind1 = mat_a->rowptr[i1+1]-mat_a->rowptr[i1]; + nind2 = mat_b->rowptr[i2+1]-mat_b->rowptr[i2]; + ind1 = mat_a->rowind + mat_a->rowptr[i1]; + ind2 = mat_b->rowind + mat_b->rowptr[i2]; + val1 = mat_a->rowval + mat_a->rowptr[i1]; + val2 = mat_b->rowval + mat_b->rowptr[i2]; + break; + + case GK_CSR_COL: + if (!mat_a->colptr || !mat_b->colptr) + gk_errexit(SIGERR, "Column-based view of the matrix does not exists.\n"); + nind1 = mat_a->colptr[i1+1]-mat_a->colptr[i1]; + nind2 = mat_b->colptr[i2+1]-mat_b->colptr[i2]; + ind1 = mat_a->colind + mat_a->colptr[i1]; + ind2 = mat_b->colind + mat_b->colptr[i2]; + val1 = mat_a->colval + mat_a->colptr[i1]; + val2 = mat_b->colval + mat_b->colptr[i2]; + break; + + default: + gk_errexit(SIGERR, "Invalid index type of %d.\n", what); + return 0.0; + } + + + switch (simtype) { + case GK_CSR_COS: + case GK_CSR_JAC: + sim = stat1 = stat2 = 0.0; + i1 = i2 = 0; + while (i1<nind1 && i2<nind2) { + if (i1 == nind1) { + stat2 += val2[i2]*val2[i2]; + i2++; + } + else if (i2 == nind2) { + stat1 += val1[i1]*val1[i1]; + i1++; + } + else if (ind1[i1] < ind2[i2]) { + stat1 += val1[i1]*val1[i1]; + i1++; + } + else if (ind1[i1] > ind2[i2]) { + stat2 += val2[i2]*val2[i2]; + i2++; + } + else { + sim += val1[i1]*val2[i2]; + stat1 += val1[i1]*val1[i1]; + stat2 += val2[i2]*val2[i2]; + i1++; + i2++; + } + } + if (simtype == GK_CSR_COS) + sim = (stat1*stat2 > 0.0 ? sim/sqrt(stat1*stat2) : 0.0); + else + sim = (stat1+stat2-sim > 0.0 ? sim/(stat1+stat2-sim) : 0.0); + break; + + case GK_CSR_MIN: + sim = stat1 = stat2 = 0.0; + i1 = i2 = 0; + while (i1<nind1 && i2<nind2) { + if (i1 == nind1) { + stat2 += val2[i2]; + i2++; + } + else if (i2 == nind2) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] < ind2[i2]) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] > ind2[i2]) { + stat2 += val2[i2]; + i2++; + } + else { + sim += gk_min(val1[i1],val2[i2]); + stat1 += val1[i1]; + stat2 += val2[i2]; + i1++; + i2++; + } + } + sim = (stat1+stat2-sim > 0.0 ? sim/(stat1+stat2-sim) : 0.0); + + break; + + case GK_CSR_AMIN: + sim = stat1 = stat2 = 0.0; + i1 = i2 = 0; + while (i1<nind1 && i2<nind2) { + if (i1 == nind1) { + stat2 += val2[i2]; + i2++; + } + else if (i2 == nind2) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] < ind2[i2]) { + stat1 += val1[i1]; + i1++; + } + else if (ind1[i1] > ind2[i2]) { + stat2 += val2[i2]; + i2++; + } + else { + sim += gk_min(val1[i1],val2[i2]); + stat1 += val1[i1]; + stat2 += val2[i2]; + i1++; + i2++; + } + } + sim = (stat1 > 0.0 ? sim/stat1 : 0.0); + + break; + + default: + gk_errexit(SIGERR, "Unknown similarity measure %d\n", simtype); + return -1; + } + + return sim; + +} + +/*************************************************************************/ +/*! Finds the n most similar rows (neighbors) to the query. + + \param mat the matrix itself + \param nqterms is the number of columns in the query + \param qind is the list of query columns + \param qval is the list of correspodning query weights + \param simtype is the type of similarity and is one of GK_CSR_DOTP, + GK_CSR_COS, GK_CSR_JAC, GK_CSR_MIN, GK_CSR_AMIN. In case of + GK_CSR_COS, the rows and the query are assumed to be of unit + length. + \param nsim is the maximum number of requested most similar rows. + If -1 is provided, then everything is returned unsorted. + \param minsim is the minimum similarity of the requested most + similar rows + \param hits is the result set. This array should be at least + of length nsim. + \param i_marker is an array of size equal to the number of rows + whose values are initialized to -1. If NULL is provided + then this array is allocated and freed internally. + \param i_cand is an array of size equal to the number of rows. + If NULL is provided then this array is allocated and freed + internally. + \returns The number of identified most similar rows, which can be + smaller than the requested number of nnbrs in those cases + in which there are no sufficiently many neighbors. +*/ +/**************************************************************************/ +int gk_csr_GetSimilarRows(gk_csr_t *mat, int nqterms, int *qind, + float *qval, int simtype, int nsim, float minsim, gk_fkv_t *hits, + int *i_marker, gk_fkv_t *i_cand) +{ + ssize_t i, ii, j, k; + int nrows, ncols, ncand; + ssize_t *colptr; + int *colind, *marker; + float *colval, *rnorms, mynorm, *rsums, mysum; + gk_fkv_t *cand; + + if (nqterms == 0) + return 0; + + nrows = mat->nrows; + ncols = mat->ncols; + GKASSERT((colptr = mat->colptr) != NULL); + GKASSERT((colind = mat->colind) != NULL); + GKASSERT((colval = mat->colval) != NULL); + + marker = (i_marker ? i_marker : gk_ismalloc(nrows, -1, "gk_csr_SimilarRows: marker")); + cand = (i_cand ? i_cand : gk_fkvmalloc(nrows, "gk_csr_SimilarRows: cand")); + + switch (simtype) { + case GK_CSR_DOTP: + case GK_CSR_COS: + for (ncand=0, ii=0; ii<nqterms; ii++) { + i = qind[ii]; + if (i < ncols) { + for (j=colptr[i]; j<colptr[i+1]; j++) { + k = colind[j]; + if (marker[k] == -1) { + cand[ncand].val = k; + cand[ncand].key = 0; + marker[k] = ncand++; + } + cand[marker[k]].key += colval[j]*qval[ii]; + } + } + } + break; + + case GK_CSR_JAC: + for (ncand=0, ii=0; ii<nqterms; ii++) { + i = qind[ii]; + if (i < ncols) { + for (j=colptr[i]; j<colptr[i+1]; j++) { + k = colind[j]; + if (marker[k] == -1) { + cand[ncand].val = k; + cand[ncand].key = 0; + marker[k] = ncand++; + } + cand[marker[k]].key += colval[j]*qval[ii]; + } + } + } + + GKASSERT((rnorms = mat->rnorms) != NULL); + mynorm = gk_fdot(nqterms, qval, 1, qval, 1); + + for (i=0; i<ncand; i++) + cand[i].key = cand[i].key/(rnorms[cand[i].val]+mynorm-cand[i].key); + break; + + case GK_CSR_MIN: + for (ncand=0, ii=0; ii<nqterms; ii++) { + i = qind[ii]; + if (i < ncols) { + for (j=colptr[i]; j<colptr[i+1]; j++) { + k = colind[j]; + if (marker[k] == -1) { + cand[ncand].val = k; + cand[ncand].key = 0; + marker[k] = ncand++; + } + cand[marker[k]].key += gk_min(colval[j], qval[ii]); + } + } + } + + GKASSERT((rsums = mat->rsums) != NULL); + mysum = gk_fsum(nqterms, qval, 1); + + for (i=0; i<ncand; i++) + cand[i].key = cand[i].key/(rsums[cand[i].val]+mysum-cand[i].key); + break; + + /* Assymetric MIN similarity */ + case GK_CSR_AMIN: + for (ncand=0, ii=0; ii<nqterms; ii++) { + i = qind[ii]; + if (i < ncols) { + for (j=colptr[i]; j<colptr[i+1]; j++) { + k = colind[j]; + if (marker[k] == -1) { + cand[ncand].val = k; + cand[ncand].key = 0; + marker[k] = ncand++; + } + cand[marker[k]].key += gk_min(colval[j], qval[ii]); + } + } + } + + mysum = gk_fsum(nqterms, qval, 1); + + for (i=0; i<ncand; i++) + cand[i].key = cand[i].key/mysum; + break; + + default: + gk_errexit(SIGERR, "Unknown similarity measure %d\n", simtype); + return -1; + } + + /* go and prune the hits that are bellow minsim */ + for (j=0, i=0; i<ncand; i++) { + marker[cand[i].val] = -1; + if (cand[i].key >= minsim) + cand[j++] = cand[i]; + } + ncand = j; + + if (nsim == -1 || nsim >= ncand) { + nsim = ncand; + } + else { + nsim = gk_min(nsim, ncand); + gk_dfkvkselect(ncand, nsim, cand); + gk_fkvsortd(nsim, cand); + } + + gk_fkvcopy(nsim, cand, hits); + + if (i_marker == NULL) + gk_free((void **)&marker, LTERM); + if (i_cand == NULL) + gk_free((void **)&cand, LTERM); + + return nsim; +} + + +/*************************************************************************/ +/*! Returns a symmetric version of a square matrix. The symmetric version + is constructed by applying an A op A^T operation, where op is one of + GK_CSR_SYM_SUM, GK_CSR_SYM_MIN, GK_CSR_SYM_MAX, GK_CSR_SYM_AVG. + + \param mat the matrix to be symmetrized, + \param op indicates the operation to be performed. The possible values are + GK_CSR_SYM_SUM, GK_CSR_SYM_MIN, GK_CSR_SYM_MAX, and GK_CSR_SYM_AVG. + + \returns the symmetrized matrix consisting only of its row-based structure. + The input matrix is not modified. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_MakeSymmetric(gk_csr_t *mat, int op) +{ + ssize_t i, j, k, nnz; + int nrows, nadj, hasvals; + ssize_t *rowptr, *colptr, *nrowptr; + int *rowind, *colind, *nrowind, *marker, *ids; + float *rowval=NULL, *colval=NULL, *nrowval=NULL, *wgts=NULL; + gk_csr_t *nmat; + + if (mat->nrows != mat->ncols) { + fprintf(stderr, "gk_csr_MakeSymmetric: The matrix needs to be square.\n"); + return NULL; + } + + hasvals = (mat->rowval != NULL); + + nrows = mat->nrows; + rowptr = mat->rowptr; + rowind = mat->rowind; + if (hasvals) + rowval = mat->rowval; + + /* create the column view for efficient processing */ + colptr = gk_zsmalloc(nrows+1, 0, "colptr"); + colind = gk_i32malloc(rowptr[nrows], "colind"); + if (hasvals) + colval = gk_fmalloc(rowptr[nrows], "colval"); + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + colptr[rowind[j]]++; + } + MAKECSR(i, nrows, colptr); + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + colind[colptr[rowind[j]]] = i; + if (hasvals) + colval[colptr[rowind[j]]] = rowval[j]; + colptr[rowind[j]]++; + } + } + SHIFTCSR(i, nrows, colptr); + + + nmat = gk_csr_Create(); + + nmat->nrows = mat->nrows; + nmat->ncols = mat->ncols; + + nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_MakeSymmetric: nrowptr"); + nrowind = nmat->rowind = gk_imalloc(2*rowptr[nrows], "gk_csr_MakeSymmetric: nrowind"); + if (hasvals) + nrowval = nmat->rowval = gk_fmalloc(2*rowptr[nrows], "gk_csr_MakeSymmetric: nrowval"); + + marker = gk_ismalloc(nrows, -1, "marker"); + ids = gk_imalloc(nrows, "ids"); + if (hasvals) + wgts = gk_fmalloc(nrows, "wgts"); + + nrowptr[0] = nnz = 0; + for (i=0; i<nrows; i++) { + nadj = 0; + /* out-edges */ + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + ids[nadj] = rowind[j]; + if (hasvals) + wgts[nadj] = (op == GK_CSR_SYM_AVG ? 0.5*rowval[j] : rowval[j]); + marker[rowind[j]] = nadj++; + } + + /* in-edges */ + for (j=colptr[i]; j<colptr[i+1]; j++) { + if (marker[colind[j]] == -1) { + if (op != GK_CSR_SYM_MIN) { + ids[nadj] = colind[j]; + if (hasvals) + wgts[nadj] = (op == GK_CSR_SYM_AVG ? 0.5*colval[j] : colval[j]); + nadj++; + } + } + else { + if (hasvals) { + switch (op) { + case GK_CSR_SYM_MAX: + wgts[marker[colind[j]]] = gk_max(colval[j], wgts[marker[colind[j]]]); + break; + case GK_CSR_SYM_MIN: + wgts[marker[colind[j]]] = gk_min(colval[j], wgts[marker[colind[j]]]); + break; + case GK_CSR_SYM_SUM: + wgts[marker[colind[j]]] += colval[j]; + break; + case GK_CSR_SYM_AVG: + wgts[marker[colind[j]]] = 0.5*(wgts[marker[colind[j]]] + colval[j]); + break; + default: + errexit("Unsupported op for MakeSymmetric!\n"); + } + } + marker[colind[j]] = -1; + } + } + + /* go over out edges again to resolve any edges that were not found in the in + * edges */ + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (marker[rowind[j]] != -1) { + if (op == GK_CSR_SYM_MIN) + ids[marker[rowind[j]]] = -1; + marker[rowind[j]] = -1; + } + } + + /* put the non '-1' entries in ids[] into i's row */ + for (j=0; j<nadj; j++) { + if (ids[j] != -1) { + nrowind[nnz] = ids[j]; + if (hasvals) + nrowval[nnz] = wgts[j]; + nnz++; + } + } + nrowptr[i+1] = nnz; + } + + gk_free((void **)&colptr, &colind, &colval, &marker, &ids, &wgts, LTERM); + + return nmat; +} + + +/*************************************************************************/ +/*! This function finds the connected components in a graph stored in + CSR format. + + \param mat is the graph structure in CSR format + \param cptr is the ptr structure of the CSR representation of the + components. The length of this vector must be mat->nrows+1. + \param cind is the indices structure of the CSR representation of + the components. The length of this vector must be mat->nrows. + \param cids is an array that stores the component # of each vertex + of the graph. The length of this vector must be mat->nrows. + + \returns the number of components that it found. + + \note The cptr, cind, and cids parameters can be NULL, in which case + only the number of connected components is returned. +*/ +/*************************************************************************/ +int gk_csr_FindConnectedComponents(gk_csr_t *mat, int32_t *cptr, int32_t *cind, + int32_t *cids) +{ + ssize_t i, ii, j, jj, k, nvtxs, first, last, ntodo, ncmps; + ssize_t *xadj; + int32_t *adjncy, *pos, *todo; + int32_t mustfree_ccsr=0, mustfree_where=0; + + if (mat->nrows != mat->ncols) { + fprintf(stderr, "gk_csr_FindComponents: The matrix needs to be square.\n"); + return -1; + } + + nvtxs = mat->nrows; + xadj = mat->rowptr; + adjncy = mat->rowind; + + /* Deal with NULL supplied cptr/cind vectors */ + if (cptr == NULL) { + cptr = gk_i32malloc(nvtxs+1, "gk_csr_FindComponents: cptr"); + cind = gk_i32malloc(nvtxs, "gk_csr_FindComponents: cind"); + mustfree_ccsr = 1; + } + + /* The list of vertices that have not been touched yet. + The valid entries are from [0..ntodo). */ + todo = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_csr_FindComponents: todo")); + + /* For a vertex that has not been visited, pos[i] is the position in the + todo list that this vertex is stored. + If a vertex has been visited, pos[i] = -1. */ + pos = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "gk_csr_FindComponents: pos")); + + + /* Find the connected componends */ + ncmps = -1; + ntodo = nvtxs; /* All vertices have not been visited */ + first = last = 0; /* Point to the first and last vertices that have been touched + but not explored. + These vertices are stored in cind[first]...cind[last-1]. */ + + while (first < last || ntodo > 0) { + if (first == last) { /* Find another starting vertex */ + cptr[++ncmps] = first; /* Mark the end of the current CC */ + + /* put the first vertex in the todo list as the start of the new CC */ + ASSERT(pos[todo[0]] != -1); + cind[last++] = todo[0]; + + pos[todo[0]] = -1; + todo[0] = todo[--ntodo]; + pos[todo[0]] = 0; + } + + i = cind[first++]; /* Get the first visited but unexplored vertex */ + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (pos[k] != -1) { + cind[last++] = k; + + /* Remove k from the todo list and put the last item in the todo + list at the position that k was so that the todo list will be + consequtive. The pos[] array is updated accordingly to keep track + the location of the vertices in the todo[] list. */ + todo[pos[k]] = todo[--ntodo]; + pos[todo[pos[k]]] = pos[k]; + pos[k] = -1; + } + } + } + cptr[++ncmps] = first; + + /* see if we need to return cids */ + if (cids != NULL) { + for (i=0; i<ncmps; i++) { + for (j=cptr[i]; j<cptr[i+1]; j++) + cids[cind[j]] = i; + } + } + + if (mustfree_ccsr) + gk_free((void **)&cptr, &cind, LTERM); + + gk_free((void **)&pos, &todo, LTERM); + + return (int) ncmps; +} + + +/*************************************************************************/ +/*! Returns a matrix that has been reordered according to the provided + row/column permutation. The matrix is required to be square and the same + permutation is applied to both rows and columns. + + \param[IN] mat is the matrix to be re-ordered. + \param[IN] perm is the new ordering of the rows & columns + \param[IN] iperm is the original ordering of the re-ordered matrix's rows & columns + \returns the newly created reordered matrix. + + \note Either perm or iperm can be NULL but not both. +*/ +/**************************************************************************/ +gk_csr_t *gk_csr_ReorderSymmetric(gk_csr_t *mat, int32_t *perm, int32_t *iperm) +{ + ssize_t j, jj; + ssize_t *rowptr, *nrowptr; + int i, k, u, v, nrows; + int freeperm=0, freeiperm=0; + int32_t *rowind, *nrowind; + float *rowval, *nrowval; + gk_csr_t *nmat; + + if (mat->nrows != mat->ncols) { + fprintf(stderr, "gk_csr_ReorderSymmetric: The matrix needs to be square.\n"); + return NULL; + } + + if (perm == NULL && iperm == NULL) + return NULL; + + nrows = mat->nrows; + rowptr = mat->rowptr; + rowind = mat->rowind; + rowval = mat->rowval; + + nmat = gk_csr_Create(); + + nmat->nrows = nrows; + nmat->ncols = nrows; + + nrowptr = nmat->rowptr = gk_zmalloc(nrows+1, "gk_csr_ReorderSymmetric: rowptr"); + nrowind = nmat->rowind = gk_i32malloc(rowptr[nrows], "gk_csr_ReorderSymmetric: rowind"); + nrowval = nmat->rowval = gk_fmalloc(rowptr[nrows], "gk_csr_ReorderSymmetric: rowval"); + + /* allocate memory for the different structures present in the matrix */ + if (mat->rlabels) + nmat->rlabels = gk_i32malloc(nrows, "gk_csr_ReorderSymmetric: rlabels"); + if (mat->rmap) + nmat->rmap = gk_i32malloc(nrows, "gk_csr_ReorderSymmetric: rmap"); + if (mat->rnorms) + nmat->rnorms = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: rnorms"); + if (mat->rsums) + nmat->rsums = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: rsums"); + if (mat->rsizes) + nmat->rsizes = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: rsizes"); + if (mat->rvols) + nmat->rvols = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: rvols"); + if (mat->rwgts) + nmat->rwgts = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: rwgts"); + + if (mat->clabels) + nmat->clabels = gk_i32malloc(nrows, "gk_csr_ReorderSymmetric: clabels"); + if (mat->cmap) + nmat->cmap = gk_i32malloc(nrows, "gk_csr_ReorderSymmetric: cmap"); + if (mat->cnorms) + nmat->cnorms = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: cnorms"); + if (mat->csums) + nmat->csums = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: csums"); + if (mat->csizes) + nmat->csizes = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: csizes"); + if (mat->cvols) + nmat->cvols = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: cvols"); + if (mat->cwgts) + nmat->cwgts = gk_fmalloc(nrows, "gk_csr_ReorderSymmetric: cwgts"); + + + + /* create perm/iperm if not provided */ + if (perm == NULL) { + freeperm = 1; + perm = gk_i32malloc(nrows, "gk_csr_ReorderSymmetric: perm"); + for (i=0; i<nrows; i++) + perm[iperm[i]] = i; + } + if (iperm == NULL) { + freeiperm = 1; + iperm = gk_i32malloc(nrows, "gk_csr_ReorderSymmetric: iperm"); + for (i=0; i<nrows; i++) + iperm[perm[i]] = i; + } + + /* fill-in the information of the re-ordered matrix */ + nrowptr[0] = jj = 0; + for (v=0; v<nrows; v++) { + u = iperm[v]; + for (j=rowptr[u]; j<rowptr[u+1]; j++, jj++) { + nrowind[jj] = perm[rowind[j]]; + nrowval[jj] = rowval[j]; + } + + if (mat->rlabels) + nmat->rlabels[v] = mat->rlabels[u]; + if (mat->rmap) + nmat->rmap[v] = mat->rmap[u]; + if (mat->rnorms) + nmat->rnorms[v] = mat->rnorms[u]; + if (mat->rsums) + nmat->rsums[v] = mat->rsums[u]; + if (mat->rsizes) + nmat->rsizes[v] = mat->rsizes[u]; + if (mat->rvols) + nmat->rvols[v] = mat->rvols[u]; + if (mat->rwgts) + nmat->rwgts[v] = mat->rwgts[u]; + + if (mat->clabels) + nmat->clabels[v] = mat->clabels[u]; + if (mat->cmap) + nmat->cmap[v] = mat->cmap[u]; + if (mat->cnorms) + nmat->cnorms[v] = mat->cnorms[u]; + if (mat->csums) + nmat->csums[v] = mat->csums[u]; + if (mat->csizes) + nmat->csizes[v] = mat->csizes[u]; + if (mat->cvols) + nmat->cvols[v] = mat->cvols[u]; + if (mat->cwgts) + nmat->cwgts[v] = mat->cwgts[u]; + + nrowptr[v+1] = jj; + } + + + /* free memory */ + if (freeperm) + gk_free((void **)&perm, LTERM); + if (freeiperm) + gk_free((void **)&iperm, LTERM); + + return nmat; +} + + +/*************************************************************************/ +/*! This function computes a permutation of the rows/columns of a symmetric + matrix based on a breadth-first-traversal. It can be used for re-ordering + the matrix to reduce its bandwidth for better cache locality. + + \param[IN] mat is the matrix whose ordering to be computed. + \param[IN] maxdegree is the maximum number of nonzeros of the rows that + will participate in the BFS ordering. Rows with more nonzeros + will be put at the front of the ordering in decreasing degree + order. + \param[IN] v is the starting row of the BFS. A value of -1 indicates that + a randomly selected row will be used. + \param[OUT] perm[i] stores the ID of row i in the re-ordered matrix. + \param[OUT] iperm[i] stores the ID of the row that corresponds to + the ith vertex in the re-ordered matrix. + + \note The perm or iperm (but not both) can be NULL, at which point, + the corresponding arrays are not returned. Though the program + works fine when both are NULL, doing that is not smart. + The returned arrays should be freed with gk_free(). +*/ +/*************************************************************************/ +void gk_csr_ComputeBFSOrderingSymmetric(gk_csr_t *mat, int maxdegree, int v, + int32_t **r_perm, int32_t **r_iperm) +{ + int i, k, nrows, first, last; + ssize_t j, *rowptr; + int32_t *rowind, *cot, *pos; + + if (mat->nrows != mat->ncols) { + fprintf(stderr, "gk_csr_ComputeBFSOrderingSymmetric: The matrix needs to be square.\n"); + return; + } + if (maxdegree < mat->nrows && v != -1) { + fprintf(stderr, "gk_csr_ComputeBFSOrderingSymmetric: Since maxdegree node renumbering is requested the starting row should be -1.\n"); + return; + } + if (mat->nrows <= 0) + return; + + nrows = mat->nrows; + rowptr = mat->rowptr; + rowind = mat->rowind; + + /* This array will function like pos + touched of the CC method */ + pos = gk_i32incset(nrows, 0, gk_i32malloc(nrows, "gk_csr_ComputeBFSOrderingSymmetric: pos")); + + /* This array ([C]losed[O]pen[T]odo => cot) serves three purposes. + Positions from [0...first) is the current iperm[] vector of the explored rows; + Positions from [first...last) is the OPEN list (i.e., visited rows); + Positions from [last...nrows) is the todo list. */ + cot = gk_i32incset(nrows, 0, gk_i32malloc(nrows, "gk_csr_ComputeBFSOrderingSymmetric: cot")); + + first = last = 0; + + /* deal with maxdegree handling */ + if (maxdegree < nrows) { + last = nrows; + for (i=nrows-1; i>=0; i--) { + if (rowptr[i+1]-rowptr[i] < maxdegree) { + cot[--last] = i; + pos[i] = last; + } + else { + cot[first++] = i; + pos[i] = -1; + } + } + GKASSERT(first == last); + + if (last > 0) { /* reorder them in degree decreasing order */ + gk_ikv_t *cand = gk_ikvmalloc(first, "gk_csr_ComputeBFSOrderingSymmetric: cand"); + + for (i=0; i<first; i++) { + k = cot[i]; + cand[i].key = (int)(rowptr[k+1]-rowptr[k]); + cand[i].val = k; + } + + gk_ikvsortd(first, cand); + for (i=0; i<first; i++) + cot[i] = cand[i].val; + + gk_free((void **)&cand, LTERM); + } + + v = cot[last + RandomInRange(nrows-last)]; + } + + + /* swap v with the front of the todo list */ + cot[pos[v]] = cot[last]; + pos[cot[last]] = pos[v]; + + cot[last] = v; + pos[v] = last; + + + /* start processing the nodes */ + while (first < nrows) { + if (first == last) { /* find another starting row */ + k = cot[last]; + GKASSERT(pos[k] != -1); + pos[k] = -1; /* mark node as being visited */ + last++; + } + + i = cot[first++]; /* the ++ advances the explored rows */ + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + k = rowind[j]; + /* if a node has already been visited, its perm[] will be -1 */ + if (pos[k] != -1) { + /* pos[k] is the location within iperm of where k resides (it is in the 'todo' part); + It is placed in that location cot[last] (end of OPEN list) that we + are about to overwrite and update pos[cot[last]] to reflect that. */ + cot[pos[k]] = cot[last]; /* put the head of the todo list to + where k was in the todo list */ + pos[cot[last]] = pos[k]; /* update perm to reflect the move */ + + cot[last++] = k; /* put node at the end of the OPEN list */ + pos[k] = -1; /* mark node as being visited */ + } + } + } + + /* time to decide what to return */ + if (r_perm != NULL) { + /* use the 'pos' array to build the perm array */ + for (i=0; i<nrows; i++) + pos[cot[i]] = i; + + *r_perm = pos; + pos = NULL; + } + + if (r_iperm != NULL) { + *r_iperm = cot; + cot = NULL; + } + + /* cleanup memory */ + gk_free((void **)&pos, &cot, LTERM); + +} + + +/*************************************************************************/ +/*! This function computes a permutation of the rows of a symmetric matrix + based on a best-first-traversal. It can be used for re-ordering the matrix + to reduce its bandwidth for better cache locality. + + \param[IN] mat is the matrix structure. + \param[IN] v is the starting row of the best-first traversal. + \param[IN] type indicates the criteria to use to measure the 'bestness' + of a row. + \param[OUT] perm[i] stores the ID of row i in the re-ordered matrix. + \param[OUT] iperm[i] stores the ID of the row that corresponds to + the ith row in the re-ordered matrix. + + \note The perm or iperm (but not both) can be NULL, at which point, + the corresponding arrays are not returned. Though the program + works fine when both are NULL, doing that is not smart. + The returned arrays should be freed with gk_free(). +*/ +/*************************************************************************/ +void gk_csr_ComputeBestFOrderingSymmetric(gk_csr_t *mat, int v, int type, + int32_t **r_perm, int32_t **r_iperm) +{ + ssize_t j, jj, *rowptr; + int i, k, u, nrows, nopen, ntodo; + int32_t *rowind, *perm, *degrees, *wdegrees, *sod, *level, *ot, *pos; + gk_i32pq_t *queue; + + if (mat->nrows != mat->ncols) { + fprintf(stderr, "gk_csr_ComputeBestFOrderingSymmetric: The matrix needs to be square.\n"); + return; + } + if (mat->nrows <= 0) + return; + + nrows = mat->nrows; + rowptr = mat->rowptr; + rowind = mat->rowind; + + + /* the degree of the vertices in the closed list */ + degrees = gk_i32smalloc(nrows, 0, "gk_csr_ComputeBestFOrderingSymmetric: degrees"); + + /* the weighted degree of the vertices in the closed list for type==3 */ + wdegrees = gk_i32smalloc(nrows, 0, "gk_csr_ComputeBestFOrderingSymmetric: wdegrees"); + + /* the sum of differences for type==4 */ + sod = gk_i32smalloc(nrows, 0, "gk_csr_ComputeBestFOrderingSymmetric: sod"); + + /* the encountering level of a vertex type==5 */ + level = gk_i32smalloc(nrows, 0, "gk_csr_ComputeBestFOrderingSymmetric: level"); + + /* The open+todo list of vertices. + The vertices from [0..nopen] are the open vertices. + The vertices from [nopen..ntodo) are the todo vertices. + */ + ot = gk_i32incset(nrows, 0, gk_i32malloc(nrows, "gk_csr_ComputeBestFOrderingSymmetric: ot")); + + /* For a vertex that has not been explored, pos[i] is the position in the ot list. */ + pos = gk_i32incset(nrows, 0, gk_i32malloc(nrows, "gk_csr_ComputeBestFOrderingSymmetric: pos")); + + /* if perm[i] >= 0, then perm[i] is the order of vertex i; otherwise perm[i] == -1. */ + perm = gk_i32smalloc(nrows, -1, "gk_csr_ComputeBestFOrderingSymmetric: perm"); + + /* create the queue and put the starting vertex in it */ + queue = gk_i32pqCreate(nrows); + gk_i32pqInsert(queue, v, 1); + + /* put v at the front of the open list */ + pos[0] = ot[0] = v; + pos[v] = ot[v] = 0; + nopen = 1; + ntodo = nrows; + + /* start processing the nodes */ + for (i=0; i<nrows; i++) { + if (nopen == 0) { /* deal with non-connected graphs */ + gk_i32pqInsert(queue, ot[0], 1); + nopen++; + } + + if ((v = gk_i32pqGetTop(queue)) == -1) + gk_errexit(SIGERR, "The priority queue got empty ahead of time [i=%d].\n", i); + + if (perm[v] != -1) + gk_errexit(SIGERR, "The perm[%d] has already been set.\n", v); + perm[v] = i; + + if (ot[pos[v]] != v) + gk_errexit(SIGERR, "Something went wrong [ot[pos[%d]]!=%d.\n", v, v); + if (pos[v] >= nopen) + gk_errexit(SIGERR, "The position of v is not in open list. pos[%d]=%d is >=%d.\n", v, pos[v], nopen); + + /* remove v from the open list and re-arrange the todo part of the list */ + ot[pos[v]] = ot[nopen-1]; + pos[ot[nopen-1]] = pos[v]; + if (ntodo > nopen) { + ot[nopen-1] = ot[ntodo-1]; + pos[ot[ntodo-1]] = nopen-1; + } + nopen--; + ntodo--; + + for (j=rowptr[v]; j<rowptr[v+1]; j++) { + u = rowind[j]; + if (perm[u] == -1) { + /* update ot list, if u is not in the open list by putting it at the end + of the open list. */ + if (degrees[u] == 0) { + ot[pos[u]] = ot[nopen]; + pos[ot[nopen]] = pos[u]; + ot[nopen] = u; + pos[u] = nopen; + nopen++; + + level[u] = level[v]+1; + gk_i32pqInsert(queue, u, 0); + } + + + /* update the in-closed degree */ + degrees[u]++; + + /* update the queues based on the type */ + switch (type) { + case 1: /* DFS */ + gk_i32pqUpdate(queue, u, 1000*(i+1)+degrees[u]); + break; + + case 2: /* Max in closed degree */ + gk_i32pqUpdate(queue, u, degrees[u]); + break; + + case 3: /* Sum of orders in closed list */ + wdegrees[u] += i; + gk_i32pqUpdate(queue, u, wdegrees[u]); + break; + + case 4: /* Sum of order-differences */ + /* this is handled at the end of the loop */ + ; + break; + + case 5: /* BFS with in degree priority */ + gk_i32pqUpdate(queue, u, -(1000*level[u] - degrees[u])); + break; + + case 6: /* Hybrid of 1+2 */ + gk_i32pqUpdate(queue, u, (i+1)*degrees[u]); + break; + + default: + ; + } + } + } + + if (type == 4) { /* update all the vertices in the open list */ + for (j=0; j<nopen; j++) { + u = ot[j]; + if (perm[u] != -1) + gk_errexit(SIGERR, "For i=%d, the open list contains a closed row: ot[%zd]=%d, perm[%d]=%d.\n", i, j, u, u, perm[u]); + sod[u] += degrees[u]; + if (i<1000 || i%25==0) + gk_i32pqUpdate(queue, u, sod[u]); + } + } + + /* + for (j=0; j<ntodo; j++) { + if (pos[ot[j]] != j) + gk_errexit(SIGERR, "pos[ot[%zd]] != %zd.\n", j, j); + } + */ + + } + + + /* time to decide what to return */ + if (r_iperm != NULL) { + /* use the 'degrees' array to build the iperm array */ + for (i=0; i<nrows; i++) + degrees[perm[i]] = i; + + *r_iperm = degrees; + degrees = NULL; + } + + if (r_perm != NULL) { + *r_perm = perm; + perm = NULL; + } + + + + + /* cleanup memory */ + gk_i32pqDestroy(queue); + gk_free((void **)&perm, °rees, &wdegrees, &sod, &ot, &pos, &level, LTERM); + +} + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/error.c b/3rdParty/metis/metis-5.1.1/GKlib/error.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/error.c rename to 3rdParty/metis/metis-5.1.1/GKlib/error.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/evaluate.c b/3rdParty/metis/metis-5.1.1/GKlib/evaluate.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/evaluate.c rename to 3rdParty/metis/metis-5.1.1/GKlib/evaluate.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/fkvkselect.c b/3rdParty/metis/metis-5.1.1/GKlib/fkvkselect.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/fkvkselect.c rename to 3rdParty/metis/metis-5.1.1/GKlib/fkvkselect.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/fs.c b/3rdParty/metis/metis-5.1.1/GKlib/fs.c similarity index 97% rename from 3rdParty/metis/metis-5.1.0/GKlib/fs.c rename to 3rdParty/metis/metis-5.1.1/GKlib/fs.c index 35e4b97b2916b27befb1f7f8d1d4284a597ecfa5..31e6d816bb2f5463be1575a8da98ba07913b861d 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/fs.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/fs.c @@ -7,7 +7,7 @@ the filesystem in a portable way. \date Started 4/10/95 \author George -\version\verbatim $Id: fs.c 10711 2011-08-31 22:23:04Z karypis $ \endverbatim +\version\verbatim $Id: fs.c 14332 2013-05-18 12:22:57Z karypis $ \endverbatim */ @@ -52,14 +52,14 @@ were any errors in stat'ing the file, -1 is returned. 63 bits (which I guess is okay for now). */ /**************************************************************************/ -intmax_t gk_getfsize(char *filename) +ssize_t gk_getfsize(char *filename) { struct stat status; - if (stat(filename, &status) == -1) + if (stat(filename, &status) == -1) return -1; - return (intmax_t)(status.st_size); + return (size_t)(status.st_size); } diff --git a/3rdParty/metis/metis-5.1.0/GKlib/getopt.c b/3rdParty/metis/metis-5.1.1/GKlib/getopt.c similarity index 99% rename from 3rdParty/metis/metis-5.1.0/GKlib/getopt.c rename to 3rdParty/metis/metis-5.1.1/GKlib/getopt.c index 437befc867623321308b98fe4798cc8abb229de0..2e7e042e4cdedd164ec728a645a4761f401752fe 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/getopt.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/getopt.c @@ -342,9 +342,10 @@ static int gk_getopt_internal(int argc, char **argv, char *optstring, if (gk_optind == 0 || !gk_getopt_initialized) { if (gk_optind == 0) gk_optind = 1; /* Don't scan ARGV[0], the program name. */ - optstring = gk_getopt_initialize (argc, argv, optstring); - gk_getopt_initialized = 1; - } + + optstring = gk_getopt_initialize (argc, argv, optstring); + gk_getopt_initialized = 1; + } /* Test whether ARGV[gk_optind] points to a non-option argument. Either it does not have option syntax, or there is an environment flag @@ -700,7 +701,7 @@ static int gk_getopt_internal(int argc, char **argv, char *optstring, else /* We already incremented `gk_optind' once; increment it again when taking next ARGV-elt as argument. */ gk_optarg = argv[gk_optind++]; - nextchar = NULL; + nextchar = NULL; } } return c; diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_arch.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_arch.h similarity index 84% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_arch.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_arch.h index 18889b64b1b04b64c87bbdc83842de1d7c144a0b..8c8ac50ed6f3e1b403ab71b6b38e377b1c0367b6 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_arch.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_arch.h @@ -4,7 +4,7 @@ \date Started 3/27/2007 \author George -\version\verbatim $Id: gk_arch.h 10711 2011-08-31 22:23:04Z karypis $ \endverbatim +\version\verbatim $Id: gk_arch.h 21637 2018-01-03 22:37:24Z karypis $ \endverbatim */ #ifndef _GK_ARCH_H_ @@ -35,6 +35,7 @@ #include "ms_stdint.h" #include "ms_inttypes.h" #include "ms_stat.h" + #include "win32/adapt.h" #else #ifndef SUNOS #include <stdint.h> @@ -43,6 +44,7 @@ #include <sys/types.h> #include <sys/resource.h> #include <sys/time.h> + #include <unistd.h> #endif @@ -58,14 +60,9 @@ typedef ptrdiff_t ssize_t; #define PTRDIFF_MAX INT64_MAX #endif -//#ifdef __MSC__ -/* MSC does not have rint() function */ -//#define rint(x) ((int)((x)+0.5)) - /* MSC does not have INFINITY defined */ -//#ifndef INFINITY -//#define INFINITY FLT_MAX -//#endif -//#endif +#ifndef INFINITY +#define INFINITY FLT_MAX +#endif #endif diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_defs.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_defs.h similarity index 67% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_defs.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_defs.h index d75e72d24b8d3a5b20ef43a30dbff977684697ef..68cb9a4cc0a12a89c423f413d29434f020868867 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_defs.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_defs.h @@ -4,7 +4,7 @@ \date Started 3/27/2007 \author George -\version\verbatim $Id: gk_defs.h 12732 2012-09-24 20:54:50Z karypis $ \endverbatim +\version\verbatim $Id: gk_defs.h 22039 2018-05-26 16:34:48Z karypis $ \endverbatim */ #ifndef _GK_DEFS_H_ @@ -41,6 +41,7 @@ /* CSR-related defines */ #define GK_CSR_ROW 1 #define GK_CSR_COL 2 +#define GK_CSR_ROWCOL 3 #define GK_CSR_MAXTF 1 #define GK_CSR_SQRT 2 @@ -53,17 +54,34 @@ #define GK_CSR_IDF2 9 #define GK_CSR_MAXTF2 10 -#define GK_CSR_COS 1 -#define GK_CSR_JAC 2 -#define GK_CSR_MIN 3 -#define GK_CSR_AMIN 4 +#define GK_CSR_DOTP 1 +#define GK_CSR_COS 2 +#define GK_CSR_JAC 3 +#define GK_CSR_MIN 4 +#define GK_CSR_AMIN 5 +#define GK_CSR_FMT_AUTO 2 #define GK_CSR_FMT_CLUTO 1 #define GK_CSR_FMT_CSR 2 #define GK_CSR_FMT_METIS 3 #define GK_CSR_FMT_BINROW 4 #define GK_CSR_FMT_BINCOL 5 +#define GK_CSR_FMT_IJV 6 +#define GK_CSR_FMT_BIJV 7 + +#define GK_CSR_SYM_SUM 1 +#define GK_CSR_SYM_MIN 2 +#define GK_CSR_SYM_MAX 3 +#define GK_CSR_SYM_AVG 4 + #define GK_GRAPH_FMT_METIS 1 +#define GK_GRAPH_FMT_IJV 2 +#define GK_GRAPH_FMT_HIJV 3 + +#define GK_GRAPH_SYM_SUM 1 +#define GK_GRAPH_SYM_MIN 2 +#define GK_GRAPH_SYM_MAX 3 +#define GK_GRAPH_SYM_AVG 4 #endif diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_externs.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_externs.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_externs.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_externs.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_getopt.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_getopt.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_getopt.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_getopt.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_macros.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_macros.h similarity index 88% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_macros.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_macros.h index d1e288bc3d412a12f69ecceed01b70c2792fc095..c3f1b45307b4df4a9e4e8db95b54b4836ea8f27e 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_macros.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_macros.h @@ -4,7 +4,7 @@ \date Started 3/27/2007 \author George -\version\verbatim $Id: gk_macros.h 10711 2011-08-31 22:23:04Z karypis $ \endverbatim +\version\verbatim $Id: gk_macros.h 15048 2013-08-31 19:38:14Z karypis $ \endverbatim */ #ifndef _GK_MACROS_H_ @@ -22,6 +22,7 @@ #define ONEOVERRANDMAX (1.0/(RAND_MAX+1.0)) #define RandomInRange(u) ((int) (ONEOVERRANDMAX*(u)*rand())) +#define RandomInRange_r(s, u) ((int) (ONEOVERRANDMAX*(u)*rand_r(s))) #define gk_abs(x) ((x) >= 0 ? (x) : -(x)) @@ -109,6 +110,12 @@ __LINE__, __FILE__); \ } +#define GKWARN(expr) \ + if (!(expr)) { \ + printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \ + __LINE__, __FILE__); \ + } + #define GKCUASSERTP(expr,msg) \ if (!(expr)) { \ printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \ @@ -117,6 +124,15 @@ printf("\n"); \ } +#define GKWARNP(expr,msg) \ + if (!(expr)) { \ + printf("***ASSERTION failed on line %d of file %s: " #expr "\n", \ + __LINE__, __FILE__); \ + printf msg ; \ + printf("\n"); \ + } + + /*------------------------------------------------------------- * Program Assertions *-------------------------------------------------------------*/ diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkblas.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkblas.h similarity index 78% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_mkblas.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_mkblas.h index 7dd96dff27b77a174dda1c70d30284ad4cfd1f53..1231669db6a10c54b061c009f95c8eef17b1389d 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkblas.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkblas.h @@ -4,7 +4,7 @@ \date Started 3/28/07 \author George -\version\verbatim $Id: gk_mkblas.h 10711 2011-08-31 22:23:04Z karypis $ \endverbatim +\version\verbatim $Id: gk_mkblas.h 16304 2014-02-25 14:27:19Z karypis $ \endverbatim */ #ifndef _GK_MKBLAS_H_ @@ -28,76 +28,78 @@ TYPE *PRFX ## incset(size_t n, TYPE baseval, TYPE *x)\ /*************************************************************************/\ /*! The macro for gk_?max()-class of routines */\ /*************************************************************************/\ -TYPE PRFX ## max(size_t n, TYPE *x)\ +TYPE PRFX ## max(size_t n, TYPE *x, size_t incx)\ {\ - size_t i, max=0; \ + size_t i;\ + TYPE max;\ \ if (n <= 0) return (TYPE) 0;\ \ - for (i=1; i<n; i++)\ - max = (x[i] > x[max] ? i : max);\ + for (max=(*x), x+=incx, i=1; i<n; i++, x+=incx)\ + max = ((*x) > max ? (*x) : max);\ \ - return x[max];\ + return max;\ }\ \ \ /*************************************************************************/\ /*! The macro for gk_?min()-class of routines */\ /*************************************************************************/\ -TYPE PRFX ## min(size_t n, TYPE *x)\ +TYPE PRFX ## min(size_t n, TYPE *x, size_t incx)\ {\ - size_t i, min=0;\ + size_t i;\ + TYPE min;\ \ if (n <= 0) return (TYPE) 0;\ \ - for (i=1; i<n; i++)\ - min = (x[i] < x[min] ? i : min);\ + for (min=(*x), x+=incx, i=1; i<n; i++, x+=incx)\ + min = ((*x) < min ? (*x) : min);\ \ - return x[min];\ + return min;\ }\ \ \ /*************************************************************************/\ /*! The macro for gk_?argmax()-class of routines */\ /*************************************************************************/\ -size_t PRFX ## argmax(size_t n, TYPE *x)\ +size_t PRFX ## argmax(size_t n, TYPE *x, size_t incx)\ {\ - size_t i, max=0;\ + size_t i, j, max=0;\ \ - for (i=1; i<n; i++)\ - max = (x[i] > x[max] ? i : max);\ + for (i=1, j=incx; i<n; i++, j+=incx)\ + max = (x[j] > x[max] ? j : max);\ \ - return max;\ + return (size_t)(max/incx);\ }\ \ \ /*************************************************************************/\ /*! The macro for gk_?argmin()-class of routines */\ /*************************************************************************/\ -size_t PRFX ## argmin(size_t n, TYPE *x)\ +size_t PRFX ## argmin(size_t n, TYPE *x, size_t incx)\ {\ - size_t i, min=0;\ + size_t i, j, min=0;\ \ - for (i=1; i<n; i++)\ - min = (x[i] < x[min] ? i : min);\ + for (i=1, j=incx; i<n; i++, j+=incx)\ + min = (x[j] < x[min] ? j : min);\ \ - return min;\ + return (size_t)(min/incx);\ }\ \ \ /*************************************************************************/\ /*! The macro for gk_?argmax_n()-class of routines */\ /*************************************************************************/\ -size_t PRFX ## argmax_n(size_t n, TYPE *x, size_t k)\ +size_t PRFX ## argmax_n(size_t n, TYPE *x, size_t incx, size_t k)\ {\ - size_t i, max_n;\ + size_t i, j, max_n;\ PRFX ## kv_t *cand;\ \ cand = PRFX ## kvmalloc(n, "GK_ARGMAX_N: cand");\ \ - for (i=0; i<n; i++) {\ + for (i=0, j=0; i<n; i++, j+=incx) {\ cand[i].val = i;\ - cand[i].key = x[i];\ + cand[i].key = x[j];\ }\ PRFX ## kvsortd(n, cand);\ \ @@ -186,11 +188,11 @@ TYPE *PRFX ## axpy(size_t n, TYPE alpha, TYPE *x, size_t incx, TYPE *y, size_t i #define GK_MKBLAS_PROTO(PRFX, TYPE, OUTTYPE) \ TYPE *PRFX ## incset(size_t n, TYPE baseval, TYPE *x);\ - TYPE PRFX ## max(size_t n, TYPE *x);\ - TYPE PRFX ## min(size_t n, TYPE *x);\ - size_t PRFX ## argmax(size_t n, TYPE *x);\ - size_t PRFX ## argmin(size_t n, TYPE *x);\ - size_t PRFX ## argmax_n(size_t n, TYPE *x, size_t k);\ + TYPE PRFX ## max(size_t n, TYPE *x, size_t incx);\ + TYPE PRFX ## min(size_t n, TYPE *x, size_t incx);\ + size_t PRFX ## argmax(size_t n, TYPE *x, size_t incx);\ + size_t PRFX ## argmin(size_t n, TYPE *x, size_t incx);\ + size_t PRFX ## argmax_n(size_t n, TYPE *x, size_t incx, size_t k);\ OUTTYPE PRFX ## sum(size_t n, TYPE *x, size_t incx);\ TYPE *PRFX ## scale(size_t n, TYPE alpha, TYPE *x, size_t incx);\ OUTTYPE PRFX ## norm2(size_t n, TYPE *x, size_t incx);\ diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkmemory.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkmemory.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_mkmemory.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_mkmemory.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkpqueue.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkpqueue.h similarity index 95% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_mkpqueue.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_mkpqueue.h index 3da7d26c05f2b04080c8de581738ce0ca817b8b3..50a5385b48568f69e58b979fac1028b4335a4d8d 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkpqueue.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkpqueue.h @@ -4,7 +4,7 @@ \date Started 4/09/07 \author George -\version\verbatim $Id: gk_mkpqueue.h 13005 2012-10-23 22:34:36Z karypis $ \endverbatim +\version\verbatim $Id: gk_mkpqueue.h 21742 2018-01-26 16:59:15Z karypis $ \endverbatim */ @@ -45,8 +45,8 @@ void FPRFX ## Init(PQT *queue, size_t maxnodes)\ /**************************************************************************/\ void FPRFX ## Reset(PQT *queue)\ {\ - gk_idx_t i;\ - gk_idx_t *locator=queue->locator;\ + ssize_t i;\ + ssize_t *locator=queue->locator;\ KVT *heap=queue->heap;\ \ for (i=queue->nnodes-1; i>=0; i--)\ @@ -92,8 +92,8 @@ size_t FPRFX ## Length(PQT *queue)\ /**************************************************************************/\ int FPRFX ## Insert(PQT *queue, VT node, KT key)\ {\ - gk_idx_t i, j;\ - gk_idx_t *locator=queue->locator;\ + ssize_t i, j;\ + ssize_t *locator=queue->locator;\ KVT *heap=queue->heap;\ \ ASSERT2(FPRFX ## CheckHeap(queue));\ @@ -127,9 +127,10 @@ int FPRFX ## Insert(PQT *queue, VT node, KT key)\ /**************************************************************************/\ int FPRFX ## Delete(PQT *queue, VT node)\ {\ - gk_idx_t i, j, nnodes;\ + ssize_t i, j;\ + size_t nnodes;\ KT newkey, oldkey;\ - gk_idx_t *locator=queue->locator;\ + ssize_t *locator=queue->locator;\ KVT *heap=queue->heap;\ \ ASSERT(locator[node] != -1);\ @@ -194,12 +195,14 @@ int FPRFX ## Delete(PQT *queue, VT node)\ /**************************************************************************/\ void FPRFX ## Update(PQT *queue, VT node, KT newkey)\ {\ - gk_idx_t i, j, nnodes;\ + ssize_t i, j;\ + size_t nnodes;\ KT oldkey;\ - gk_idx_t *locator=queue->locator;\ + ssize_t *locator=queue->locator;\ KVT *heap=queue->heap;\ \ oldkey = heap[locator[node]].key;\ + if (!KEY_LT(newkey, oldkey) && !KEY_LT(oldkey, newkey)) return;\ \ ASSERT(locator[node] != -1);\ ASSERT(heap[locator[node]].val == node);\ @@ -256,8 +259,8 @@ void FPRFX ## Update(PQT *queue, VT node, KT newkey)\ /**************************************************************************/\ VT FPRFX ## GetTop(PQT *queue)\ {\ - gk_idx_t i, j;\ - gk_idx_t *locator;\ + ssize_t i, j;\ + ssize_t *locator;\ KVT *heap;\ VT vtx, node;\ KT key;\ @@ -332,7 +335,7 @@ KT FPRFX ## SeeTopKey(PQT *queue)\ /**************************************************************************/\ KT FPRFX ## SeeKey(PQT *queue, VT node)\ {\ - gk_idx_t *locator;\ + ssize_t *locator;\ KVT *heap;\ \ heap = queue->heap;\ @@ -350,7 +353,7 @@ KT FPRFX ## SeeKey(PQT *queue, VT node)\ /*\ VT FPRFX ## SeeConstraintTop(PQT *queue, KT maxwgt, KT *wgts)\ {\ - gk_idx_t i;\ + ssize_t i;\ \ if (queue->nnodes == 0)\ return -1;\ @@ -380,9 +383,9 @@ VT FPRFX ## SeeConstraintTop(PQT *queue, KT maxwgt, KT *wgts)\ /**************************************************************************/\ int FPRFX ## CheckHeap(PQT *queue)\ {\ - gk_idx_t i, j;\ + ssize_t i, j;\ size_t nnodes;\ - gk_idx_t *locator;\ + ssize_t *locator;\ KVT *heap;\ \ heap = queue->heap;\ diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkpqueue2.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkpqueue2.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_mkpqueue2.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_mkpqueue2.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkrandom.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkrandom.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_mkrandom.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_mkrandom.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_mksort.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_mksort.h similarity index 96% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_mksort.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_mksort.h index 56ac0b11a0554f9672686f23da22a737b6ecf642..48674db676b76489f2490ab406a7f15d9cece6b7 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_mksort.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_mksort.h @@ -4,15 +4,14 @@ \date Started 3/28/07 \author George -\version\verbatim $Id: gk_mksort.h 10711 2011-08-31 22:23:04Z karypis $ \endverbatim +\version\verbatim $Id: gk_mksort.h 21051 2017-05-25 04:36:14Z karypis $ \endverbatim */ #ifndef _GK_MKSORT_H_ #define _GK_MKSORT_H_ -/* $Id: gk_mksort.h 10711 2011-08-31 22:23:04Z karypis $ - * Adopted from GNU glibc by Mjt. +/* Adopted from GNU glibc by Mjt. * See stdlib/qsort.c in glibc */ /* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc. @@ -105,9 +104,8 @@ /* Swap two items pointed to by A and B using temporary buffer t. */ #define _GKQSORT_SWAP(a, b, t) ((void)((t = *a), (*a = *b), (*b = t))) -/* Discontinue quicksort algorithm when partition gets below this size. - This particular magic number was chosen to work best on a Sun 4/260. */ -#define _GKQSORT_MAX_THRESH 4 +/* Discontinue quicksort algorithm when partition gets below this size. */ +#define _GKQSORT_MAX_THRESH 8 /* The next 4 #defines implement a very fast in-line stack abstraction. */ #define _GKQSORT_STACK_SIZE (8 * sizeof(size_t)) @@ -123,7 +121,7 @@ const size_t _elems = (GKQSORT_NELT); \ GKQSORT_TYPE _hold; \ \ - if (_elems == 0) \ + if (_elems < 1) \ return; \ \ /* Don't declare two variables of type GKQSORT_TYPE in a single \ diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_mkutils.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_mkutils.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_mkutils.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_mkutils.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_proto.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_proto.h similarity index 77% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_proto.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_proto.h index 2cc299d4c605400b97c48e243c490a2d134b6897..d99bd5ee916f70e6f9994c00e7a3fa4d831d21b3 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_proto.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_proto.h @@ -4,7 +4,7 @@ \date Started 3/27/2007 \author George -\version\verbatim $Id: gk_proto.h 12591 2012-09-01 19:03:15Z karypis $ \endverbatim +\version\verbatim $Id: gk_proto.h 22010 2018-05-14 20:20:26Z karypis $ \endverbatim */ #ifndef _GK_PROTO_H_ @@ -19,9 +19,12 @@ extern "C" { *-------------------------------------------------------------*/ GK_MKBLAS_PROTO(gk_c, char, int) GK_MKBLAS_PROTO(gk_i, int, int) +GK_MKBLAS_PROTO(gk_i8, int8_t, int8_t) +GK_MKBLAS_PROTO(gk_i16, int16_t, int16_t) GK_MKBLAS_PROTO(gk_i32, int32_t, int32_t) GK_MKBLAS_PROTO(gk_i64, int64_t, int64_t) GK_MKBLAS_PROTO(gk_z, ssize_t, ssize_t) +GK_MKBLAS_PROTO(gk_zu, size_t, size_t) GK_MKBLAS_PROTO(gk_f, float, float) GK_MKBLAS_PROTO(gk_d, double, double) GK_MKBLAS_PROTO(gk_idx, gk_idx_t, gk_idx_t) @@ -34,15 +37,23 @@ GK_MKBLAS_PROTO(gk_idx, gk_idx_t, gk_idx_t) *-------------------------------------------------------------*/ FILE *gk_fopen(char *, char *, const char *); void gk_fclose(FILE *); +ssize_t gk_read(int fd, void *vbuf, size_t count); +ssize_t gk_write(int fd, void *vbuf, size_t count); gk_idx_t gk_getline(char **lineptr, size_t *n, FILE *stream); -char **gk_readfile(char *fname, gk_idx_t *r_nlines); -int32_t *gk_i32readfile(char *fname, gk_idx_t *r_nlines); -int64_t *gk_i64readfile(char *fname, gk_idx_t *r_nlines); -int32_t *gk_i32readfilebin(char *fname, ssize_t *r_nelmnts); -int64_t *gk_i64readfilebin(char *fname, ssize_t *r_nelmnts); -float *gk_freadfilebin(char *fname, ssize_t *r_nelmnts); +char **gk_readfile(char *fname, size_t *r_nlines); +int32_t *gk_i32readfile(char *fname, size_t *r_nlines); +int64_t *gk_i64readfile(char *fname, size_t *r_nlines); +ssize_t *gk_zreadfile(char *fname, size_t *r_nlines); +int32_t *gk_i32readfilebin(char *fname, size_t *r_nelmnts); +size_t gk_i32writefilebin(char *fname, size_t n, int32_t *a); +int64_t *gk_i64readfilebin(char *fname, size_t *r_nelmnts); +size_t gk_i64writefilebin(char *fname, size_t n, int64_t *a); +ssize_t *gk_zreadfilebin(char *fname, size_t *r_nelmnts); +size_t gk_zwritefilebin(char *fname, size_t n, ssize_t *a); +float *gk_freadfilebin(char *fname, size_t *r_nelmnts); size_t gk_fwritefilebin(char *fname, size_t n, float *a); -double *gk_dreadfilebin(char *fname, ssize_t *r_nelmnts); +double *gk_dreadfilebin(char *fname, size_t *r_nelmnts); +size_t gk_dwritefilebin(char *fname, size_t n, double *a); @@ -52,7 +63,7 @@ double *gk_dreadfilebin(char *fname, ssize_t *r_nelmnts); *-------------------------------------------------------------*/ int gk_fexists(char *); int gk_dexists(char *); -intmax_t gk_getfsize(char *); +ssize_t gk_getfsize(char *); void gk_getfilestats(char *fname, size_t *r_nlines, size_t *r_ntokens, size_t *r_max_nlntokens, size_t *r_nbytes); char *gk_getbasename(char *path); @@ -67,20 +78,30 @@ int gk_rmpath(char *); /*------------------------------------------------------------- * memory.c *-------------------------------------------------------------*/ -GK_MKALLOC_PROTO(gk_c, char) -GK_MKALLOC_PROTO(gk_i, int) -GK_MKALLOC_PROTO(gk_i32, int32_t) -GK_MKALLOC_PROTO(gk_i64, int64_t) -GK_MKALLOC_PROTO(gk_z, ssize_t) -GK_MKALLOC_PROTO(gk_f, float) -GK_MKALLOC_PROTO(gk_d, double) -GK_MKALLOC_PROTO(gk_idx, gk_idx_t) +GK_MKALLOC_PROTO(gk_c, char) +GK_MKALLOC_PROTO(gk_i, int) +GK_MKALLOC_PROTO(gk_i8, int8_t) +GK_MKALLOC_PROTO(gk_i16, int16_t) +GK_MKALLOC_PROTO(gk_i32, int32_t) +GK_MKALLOC_PROTO(gk_i64, int64_t) +GK_MKALLOC_PROTO(gk_ui8, uint8_t) +GK_MKALLOC_PROTO(gk_ui16, uint16_t) +GK_MKALLOC_PROTO(gk_ui32, uint32_t) +GK_MKALLOC_PROTO(gk_ui64, uint64_t) +GK_MKALLOC_PROTO(gk_z, ssize_t) +GK_MKALLOC_PROTO(gk_zu, size_t) +GK_MKALLOC_PROTO(gk_f, float) +GK_MKALLOC_PROTO(gk_d, double) +GK_MKALLOC_PROTO(gk_idx, gk_idx_t) GK_MKALLOC_PROTO(gk_ckv, gk_ckv_t) GK_MKALLOC_PROTO(gk_ikv, gk_ikv_t) +GK_MKALLOC_PROTO(gk_i8kv, gk_i8kv_t) +GK_MKALLOC_PROTO(gk_i16kv, gk_i16kv_t) GK_MKALLOC_PROTO(gk_i32kv, gk_i32kv_t) GK_MKALLOC_PROTO(gk_i64kv, gk_i64kv_t) GK_MKALLOC_PROTO(gk_zkv, gk_zkv_t) +GK_MKALLOC_PROTO(gk_zukv, gk_zukv_t) GK_MKALLOC_PROTO(gk_fkv, gk_fkv_t) GK_MKALLOC_PROTO(gk_dkv, gk_dkv_t) GK_MKALLOC_PROTO(gk_skv, gk_skv_t) @@ -95,6 +116,7 @@ void *gk_realloc(void *oldptr, size_t nbytes, char *msg); void gk_free(void **ptr1,...); size_t gk_GetCurMemoryUsed(); size_t gk_GetMaxMemoryUsed(); +void gk_GetVMInfo(size_t *vmsize, size_t *vmrss); @@ -107,19 +129,6 @@ void gk_seq_init(gk_seq_t *seq); - -/*------------------------------------------------------------- - * pdb.c - *-------------------------------------------------------------*/ -char gk_threetoone(char *res); -void gk_freepdbf(pdbf *p); -pdbf *gk_readpdbfile(char *fname); -void gk_writefullatom(pdbf *p, char *fname); -void gk_writebackbone(pdbf *p, char *fname); -void gk_writealphacarbons(pdbf *p, char *fname); -void gk_showcorruption(pdbf *p); - - /*------------------------------------------------------------- * error.c *-------------------------------------------------------------*/ @@ -177,6 +186,14 @@ void gk_csorti(size_t, char *); void gk_csortd(size_t, char *); void gk_isorti(size_t, int *); void gk_isortd(size_t, int *); +void gk_i32sorti(size_t, int32_t *); +void gk_i32sortd(size_t, int32_t *); +void gk_i64sorti(size_t, int64_t *); +void gk_i64sortd(size_t, int64_t *); +void gk_ui32sorti(size_t, uint32_t *); +void gk_ui32sortd(size_t, uint32_t *); +void gk_ui64sorti(size_t, uint64_t *); +void gk_ui64sortd(size_t, uint64_t *); void gk_fsorti(size_t, float *); void gk_fsortd(size_t, float *); void gk_dsorti(size_t, double *); @@ -193,6 +210,8 @@ void gk_i64kvsorti(size_t, gk_i64kv_t *); void gk_i64kvsortd(size_t, gk_i64kv_t *); void gk_zkvsorti(size_t, gk_zkv_t *); void gk_zkvsortd(size_t, gk_zkv_t *); +void gk_zukvsorti(size_t, gk_zukv_t *); +void gk_zukvsortd(size_t, gk_zukv_t *); void gk_fkvsorti(size_t, gk_fkv_t *); void gk_fkvsortd(size_t, gk_fkv_t *); void gk_dkvsorti(size_t, gk_dkv_t *); @@ -256,10 +275,12 @@ void GKDecodeBase64(int nbytes, unsigned char *inbuffer, unsigned char *outbuffe *-------------------------------------------------------------*/ GK_MKRANDOM_PROTO(gk_c, size_t, char) GK_MKRANDOM_PROTO(gk_i, size_t, int) +GK_MKRANDOM_PROTO(gk_i32, size_t, int32_t) GK_MKRANDOM_PROTO(gk_f, size_t, float) GK_MKRANDOM_PROTO(gk_d, size_t, double) GK_MKRANDOM_PROTO(gk_idx, size_t, gk_idx_t) GK_MKRANDOM_PROTO(gk_z, size_t, ssize_t) +GK_MKRANDOM_PROTO(gk_zu, size_t, size_t) void gk_randinit(uint64_t); uint64_t gk_randint64(void); uint32_t gk_randint32(void); @@ -294,6 +315,7 @@ gk_csr_t *gk_csr_ExtractSubmatrix(gk_csr_t *mat, int rstart, int nrows); gk_csr_t *gk_csr_ExtractRows(gk_csr_t *mat, int nrows, int *rind); gk_csr_t *gk_csr_ExtractPartition(gk_csr_t *mat, int *part, int pid); gk_csr_t **gk_csr_Split(gk_csr_t *mat, int *color); +int gk_csr_DetermineFormat(char *filename, int format); gk_csr_t *gk_csr_Read(char *filename, int format, int readvals, int numbering); void gk_csr_Write(gk_csr_t *mat, char *filename, int format, int writevals, int numbering); gk_csr_t *gk_csr_Prune(gk_csr_t *mat, int what, int minf, int maxf); @@ -306,12 +328,23 @@ void gk_csr_CreateIndex(gk_csr_t *mat, int what); void gk_csr_Normalize(gk_csr_t *mat, int what, int norm); void gk_csr_Scale(gk_csr_t *mat, int type); void gk_csr_ComputeSums(gk_csr_t *mat, int what); +void gk_csr_ComputeNorms(gk_csr_t *mat, int what); void gk_csr_ComputeSquaredNorms(gk_csr_t *mat, int what); +gk_csr_t *gk_csr_Shuffle(gk_csr_t *mat, int what, int summetric); +gk_csr_t *gk_csr_Transpose(gk_csr_t *mat); float gk_csr_ComputeSimilarity(gk_csr_t *mat, int i1, int i2, int what, int simtype); +float gk_csr_ComputePairSimilarity(gk_csr_t *mat_a, gk_csr_t *mat_b, int i1, int i2, int what, int simtype); int gk_csr_GetSimilarRows(gk_csr_t *mat, int nqterms, int *qind, float *qval, int simtype, int nsim, float minsim, gk_fkv_t *hits, int *_imarker, gk_fkv_t *i_cand); - +int gk_csr_FindConnectedComponents(gk_csr_t *mat, int32_t *cptr, int32_t *cind, + int32_t *cids); +gk_csr_t *gk_csr_MakeSymmetric(gk_csr_t *mat, int op); +gk_csr_t *gk_csr_ReorderSymmetric(gk_csr_t *mat, int32_t *perm, int32_t *iperm); +void gk_csr_ComputeBFSOrderingSymmetric(gk_csr_t *mat, int maxdegree, int v, + int32_t **r_perm, int32_t **r_iperm); +void gk_csr_ComputeBestFOrderingSymmetric(gk_csr_t *mat, int v, int type, + int32_t **r_perm, int32_t **r_iperm); /* itemsets.c */ @@ -354,10 +387,11 @@ gk_graph_t *gk_graph_Create(); void gk_graph_Init(gk_graph_t *graph); void gk_graph_Free(gk_graph_t **graph); void gk_graph_FreeContents(gk_graph_t *graph); -gk_graph_t *gk_graph_Read(char *filename, int format, int isfewgts, - int isfvwgts, int isfvsizes); -void gk_graph_Write(gk_graph_t *graph, char *filename, int format); +gk_graph_t *gk_graph_Read(char *filename, int format, int hasvals, + int numbering, int isfewgts, int isfvwgts, int isfvsizes); +void gk_graph_Write(gk_graph_t *graph, char *filename, int format, int numbering); gk_graph_t *gk_graph_Dup(gk_graph_t *graph); +gk_graph_t *gk_graph_Transpose(gk_graph_t *graph); gk_graph_t *gk_graph_ExtractSubgraph(gk_graph_t *graph, int vstart, int nvtxs); gk_graph_t *gk_graph_Reorder(gk_graph_t *graph, int32_t *perm, int32_t *iperm); int gk_graph_FindComponents(gk_graph_t *graph, int32_t *cptr, int32_t *cind); @@ -368,8 +402,16 @@ void gk_graph_ComputeBestFOrdering0(gk_graph_t *graph, int v, int type, void gk_graph_ComputeBestFOrdering(gk_graph_t *graph, int v, int type, int32_t **r_perm, int32_t **r_iperm); void gk_graph_SingleSourceShortestPaths(gk_graph_t *graph, int v, void **r_sps); +void gk_graph_SortAdjacencies(gk_graph_t *graph); +gk_graph_t *gk_graph_MakeSymmetric(gk_graph_t *graph, int op); +/* cache.c */ +gk_cache_t *gk_cacheCreate(uint32_t nway, uint32_t lnbits, size_t cnbits); +void gk_cacheReset(gk_cache_t *cache); +void gk_cacheDestroy(gk_cache_t **r_cache); +int gk_cacheLoad(gk_cache_t *cache, size_t addr); +double gk_cacheGetHitRate(gk_cache_t *cache); #ifdef __cplusplus diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_struct.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_struct.h similarity index 86% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_struct.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_struct.h index 3ef7bbd7bfe130666fa852ae216886fbf804bc4d..2925e98291b7ca98f67307b848f4380fb17d5cc1 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/gk_struct.h +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_struct.h @@ -4,7 +4,7 @@ \date Started 3/27/2007 \author George -\version\verbatim $Id: gk_struct.h 13005 2012-10-23 22:34:36Z karypis $ \endverbatim +\version\verbatim $Id: gk_struct.h 21988 2018-04-16 00:11:19Z karypis $ \endverbatim */ #ifndef _GK_STRUCT_H_ @@ -23,9 +23,12 @@ typedef struct {\ /* The actual KeyVal data structures */ GK_MKKEYVALUE_T(gk_ckv_t, char, ssize_t) GK_MKKEYVALUE_T(gk_ikv_t, int, ssize_t) +GK_MKKEYVALUE_T(gk_i8kv_t, int8_t, ssize_t) +GK_MKKEYVALUE_T(gk_i16kv_t, int16_t, ssize_t) GK_MKKEYVALUE_T(gk_i32kv_t, int32_t, ssize_t) GK_MKKEYVALUE_T(gk_i64kv_t, int64_t, ssize_t) GK_MKKEYVALUE_T(gk_zkv_t, ssize_t, ssize_t) +GK_MKKEYVALUE_T(gk_zukv_t, size_t, ssize_t) GK_MKKEYVALUE_T(gk_fkv_t, float, ssize_t) GK_MKKEYVALUE_T(gk_dkv_t, double, ssize_t) GK_MKKEYVALUE_T(gk_skv_t, char *, ssize_t) @@ -38,12 +41,12 @@ GK_MKKEYVALUE_T(gk_idxkv_t, gk_idx_t, gk_idx_t) /********************************************************************/ #define GK_MKPQUEUE_T(NAME, KVTYPE)\ typedef struct {\ - gk_idx_t nnodes;\ - gk_idx_t maxnodes;\ + size_t nnodes;\ + size_t maxnodes;\ \ /* Heap version of the data structure */ \ KVTYPE *heap;\ - gk_idx_t *locator;\ + ssize_t *locator;\ } NAME;\ GK_MKPQUEUE_T(gk_ipq_t, gk_ikv_t) @@ -74,6 +77,8 @@ typedef struct gk_csr_t { ssize_t *rowptr, *colptr; int32_t *rowind, *colind; int32_t *rowids, *colids; + int32_t *rlabels, *clabels; + int32_t *rmap, *cmap; float *rowval, *colval; float *rnorms, *cnorms; float *rsums, *csums; @@ -142,6 +147,7 @@ typedef struct gk_Tokens_t { char **list; /* Pointers to the strbuf for each element */ } gk_Tokens_t; + /*------------------------------------------------------------ * This structure implements storage for an atom in a pdb file *------------------------------------------------------------*/ @@ -237,7 +243,8 @@ typedef struct gk_mop_t { /*************************************************************************/ -/*! The following structure stores information used by Metis */ +/*! The following structure defines the mcore for GKlib's customized + memory allocations. */ /*************************************************************************/ typedef struct gk_mcore_t { /* Workspace information */ @@ -264,5 +271,26 @@ typedef struct gk_mcore_t { } gk_mcore_t; +/*************************************************************************/ +/*! The following structure is used for cache simulation for performance + modeling and analysis. */ +/*************************************************************************/ +typedef struct gk_cache_t { + /*! The total cache is nway*(2^(cnbits+lnbits)) bytes */ + uint32_t nway; /*!< the associativity of the cache */ + uint32_t lnbits; /*!< the number of address bits indexing the cache line */ + uint32_t cnbits; /*!< the number of address bits indexing the cache */ + size_t csize; /*!< 2^cnbits */ + size_t cmask; /*!< csize-1 */ + + uint64_t clock; /*!< a clock in terms of accesses */ + + uint64_t *latimes; /*!< a cacheline-level last access time */ + size_t *clines; /*!< the cache in terms of cachelines */ + + uint64_t nhits; /*!< counts the number of hits */ + uint64_t nmisses; /*!< counts the number of misses */ +} gk_cache_t; + #endif diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gk_types.h b/3rdParty/metis/metis-5.1.1/GKlib/gk_types.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gk_types.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_types.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/util.c b/3rdParty/metis/metis-5.1.1/GKlib/gk_util.c similarity index 95% rename from 3rdParty/metis/metis-5.1.0/GKlib/util.c rename to 3rdParty/metis/metis-5.1.1/GKlib/gk_util.c index e75d68b51bbdd1010fd47fcd1a9ef04eb8d23508..e1e68db0e0397643c091e3713a7c0c6f0ac9e85a 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/util.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/gk_util.c @@ -4,14 +4,13 @@ \date Started 4/12/2007 \author George -\version\verbatim $Id: util.c 10711 2011-08-31 22:23:04Z karypis $ \endverbatim +\version\verbatim $Id: gk_util.c 16223 2014-02-15 21:34:09Z karypis $ \endverbatim */ #include <GKlib.h> - /************************************************************************* * This file randomly permutes the contents of an array. * flag == 0, don't initialize perm @@ -19,7 +18,7 @@ **************************************************************************/ void gk_RandomPermute(size_t n, int *p, int flag) { - gk_idx_t i, u, v; + size_t i, u, v; int tmp; if (flag == 1) { @@ -61,7 +60,7 @@ store in CSF format the list of elements belonging in each partition. /************************************************************************/ void gk_array2csr(size_t n, size_t range, int *array, int *ptr, int *ind) { - gk_idx_t i; + size_t i; gk_iset(range+1, 0, ptr); @@ -76,13 +75,12 @@ void gk_array2csr(size_t n, size_t range, int *array, int *ptr, int *ind) } - /************************************************************************* * This function returns the log2(x) **************************************************************************/ int gk_log2(int a) { - gk_idx_t i; + size_t i; for (i=1; a > 1; i++, a = a>>1); return i-1; @@ -106,3 +104,4 @@ float gk_flog2(float a) return log(a)/log(2.0); } + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gkregex.c b/3rdParty/metis/metis-5.1.1/GKlib/gkregex.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gkregex.c rename to 3rdParty/metis/metis-5.1.1/GKlib/gkregex.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/gkregex.h b/3rdParty/metis/metis-5.1.1/GKlib/gkregex.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/gkregex.h rename to 3rdParty/metis/metis-5.1.1/GKlib/gkregex.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/graph.c b/3rdParty/metis/metis-5.1.1/GKlib/graph.c similarity index 65% rename from 3rdParty/metis/metis-5.1.0/GKlib/graph.c rename to 3rdParty/metis/metis-5.1.1/GKlib/graph.c index 209581865e4de099038c1612e21f17aceae5e454..1bfd0cc45b294444bb76709eb52cf941dea2ddac 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/graph.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/graph.c @@ -4,7 +4,7 @@ * \brief Various routines with dealing with sparse graphs * * \author George Karypis - * \version\verbatim $Id: graph.c 13328 2012-12-31 14:57:40Z karypis $ \endverbatim + * \version\verbatim $Id: graph.c 22415 2019-09-05 16:55:00Z karypis $ \endverbatim */ #include <GKlib.h> @@ -75,21 +75,24 @@ void gk_graph_FreeContents(gk_graph_t *graph) /*! Reads a sparse graph from the supplied file \param filename is the file that stores the data. \param format is the graph format. The supported values are: - GK_GRAPH_FMT_METIS. + GK_GRAPH_FMT_METIS, GK_GRAPH_FMT_IJV. + \param hasvals is 1 if the input file has values + \param numbering is 1 if the input file numbering starts from one \param isfewgts is 1 if the edge-weights should be read as floats \param isfvwgts is 1 if the vertex-weights should be read as floats \param isfvsizes is 1 if the vertex-sizes should be read as floats \returns the graph that was read. */ /**************************************************************************/ -gk_graph_t *gk_graph_Read(char *filename, int format, int isfewgts, - int isfvwgts, int isfvsizes) +gk_graph_t *gk_graph_Read(char *filename, int format, int hasvals, + int numbering, int isfewgts, int isfvwgts, int isfvsizes) { ssize_t i, k, l; size_t nfields, nvtxs, nedges, fmt, ncon, lnlen; - int32_t ival; - float fval; - int readsizes=0, readwgts=0, readvals=0, numbering=0; + ssize_t *xadj; + int32_t ival, *iinds=NULL, *jinds=NULL, *ivals=NULL, *adjncy, *iadjwgt; + float fval, *fvals=NULL, *fadjwgt; + int readsizes=0, readwgts=0, readvals=0; char *line=NULL, *head, *tail, fmtstr[256]; FILE *fpin=NULL; gk_graph_t *graph=NULL; @@ -98,169 +101,262 @@ gk_graph_t *gk_graph_Read(char *filename, int format, int isfewgts, if (!gk_fexists(filename)) gk_errexit(SIGERR, "File %s does not exist!\n", filename); - if (format == GK_GRAPH_FMT_METIS) { - fpin = gk_fopen(filename, "r", "gk_graph_Read: fpin"); - do { - if (gk_getline(&line, &lnlen, fpin) <= 0) - gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename); - } while (line[0] == '%'); - - fmt = ncon = 0; - nfields = sscanf(line, "%zu %zu %zu %zu", &nvtxs, &nedges, &fmt, &ncon); - if (nfields < 2) - gk_errexit(SIGERR, "Header line must contain at least 2 integers (#vtxs and #edges).\n"); - - nedges *= 2; - - if (fmt > 111) - gk_errexit(SIGERR, "Cannot read this type of file format [fmt=%zu]!\n", fmt); - - sprintf(fmtstr, "%03zu", fmt%1000); - readsizes = (fmtstr[0] == '1'); - readwgts = (fmtstr[1] == '1'); - readvals = (fmtstr[2] == '1'); - numbering = 1; - ncon = (ncon == 0 ? 1 : ncon); - } - else { - gk_errexit(SIGERR, "Unrecognized format: %d\n", format); - } - - graph = gk_graph_Create(); - - graph->nvtxs = nvtxs; - - graph->xadj = gk_zmalloc(nvtxs+1, "gk_graph_Read: xadj"); - graph->adjncy = gk_i32malloc(nedges, "gk_graph_Read: adjncy"); - if (readvals) { - if (isfewgts) - graph->fadjwgt = gk_fmalloc(nedges, "gk_graph_Read: fadjwgt"); - else - graph->iadjwgt = gk_i32malloc(nedges, "gk_graph_Read: iadjwgt"); - } - - if (readsizes) { - if (isfvsizes) - graph->fvsizes = gk_fmalloc(nvtxs, "gk_graph_Read: fvsizes"); - else - graph->ivsizes = gk_i32malloc(nvtxs, "gk_graph_Read: ivsizes"); - } - - if (readwgts) { - if (isfvwgts) - graph->fvwgts = gk_fmalloc(nvtxs*ncon, "gk_graph_Read: fvwgts"); - else - graph->ivwgts = gk_i32malloc(nvtxs*ncon, "gk_graph_Read: ivwgts"); - } - - - /*---------------------------------------------------------------------- - * Read the sparse graph file - *---------------------------------------------------------------------*/ - numbering = (numbering ? - 1 : 0); - for (graph->xadj[0]=0, k=0, i=0; i<nvtxs; i++) { - do { - if (gk_getline(&line, &lnlen, fpin) == -1) - gk_errexit(SIGERR, "Pregraphure end of input file: file while reading row %d\n", i); - } while (line[0] == '%'); - - head = line; - tail = NULL; - - /* Read vertex sizes */ - if (readsizes) { - if (isfvsizes) { + switch (format) { + case GK_GRAPH_FMT_METIS: + fpin = gk_fopen(filename, "r", "gk_graph_Read: fpin"); + do { + if (gk_getline(&line, &lnlen, fpin) <= 0) + gk_errexit(SIGERR, "Premature end of input file: file:%s\n", filename); + } while (line[0] == '%'); + + fmt = ncon = 0; + nfields = sscanf(line, "%zu %zu %zu %zu", &nvtxs, &nedges, &fmt, &ncon); + if (nfields < 2) + gk_errexit(SIGERR, "Header line must contain at least 2 integers (#vtxs and #edges).\n"); + + nedges *= 2; + + if (fmt > 111) + gk_errexit(SIGERR, "Cannot read this type of file format [fmt=%zu]!\n", fmt); + + sprintf(fmtstr, "%03zu", fmt%1000); + readsizes = (fmtstr[0] == '1'); + readwgts = (fmtstr[1] == '1'); + readvals = (fmtstr[2] == '1'); + numbering = 1; + ncon = (ncon == 0 ? 1 : ncon); + + graph = gk_graph_Create(); + + graph->nvtxs = nvtxs; + + graph->xadj = gk_zmalloc(nvtxs+1, "gk_graph_Read: xadj"); + graph->adjncy = gk_i32malloc(nedges, "gk_graph_Read: adjncy"); + if (readvals) { + if (isfewgts) + graph->fadjwgt = gk_fmalloc(nedges, "gk_graph_Read: fadjwgt"); + else + graph->iadjwgt = gk_i32malloc(nedges, "gk_graph_Read: iadjwgt"); + } + + if (readsizes) { + if (isfvsizes) + graph->fvsizes = gk_fmalloc(nvtxs, "gk_graph_Read: fvsizes"); + else + graph->ivsizes = gk_i32malloc(nvtxs, "gk_graph_Read: ivsizes"); + } + + if (readwgts) { + if (isfvwgts) + graph->fvwgts = gk_fmalloc(nvtxs*ncon, "gk_graph_Read: fvwgts"); + else + graph->ivwgts = gk_i32malloc(nvtxs*ncon, "gk_graph_Read: ivwgts"); + } + + + /*---------------------------------------------------------------------- + * Read the sparse graph file + *---------------------------------------------------------------------*/ + numbering = (numbering ? - 1 : 0); + for (graph->xadj[0]=0, k=0, i=0; i<nvtxs; i++) { + do { + if (gk_getline(&line, &lnlen, fpin) == -1) + gk_errexit(SIGERR, "Pregraphure end of input file: file while reading row %d\n", i); + } while (line[0] == '%'); + + head = line; + tail = NULL; + + /* Read vertex sizes */ + if (readsizes) { + if (isfvsizes) { #ifdef __MSC__ - graph->fvsizes[i] = (float)strtod(head, &tail); + graph->fvsizes[i] = (float)strtod(head, &tail); #else - graph->fvsizes[i] = strtof(head, &tail); + graph->fvsizes[i] = strtof(head, &tail); #endif - if (tail == head) - gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1); - if (graph->fvsizes[i] < 0) - gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1); - } - else { - graph->ivsizes[i] = strtol(head, &tail, 0); - if (tail == head) - gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1); - if (graph->ivsizes[i] < 0) - gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1); - } - head = tail; - } - - /* Read vertex weights */ - if (readwgts) { - for (l=0; l<ncon; l++) { - if (isfvwgts) { + if (tail == head) + gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1); + if (graph->fvsizes[i] < 0) + gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1); + } + else { + graph->ivsizes[i] = strtol(head, &tail, 0); + if (tail == head) + gk_errexit(SIGERR, "The line for vertex %zd does not have size information\n", i+1); + if (graph->ivsizes[i] < 0) + gk_errexit(SIGERR, "The size for vertex %zd must be >= 0\n", i+1); + } + head = tail; + } + + /* Read vertex weights */ + if (readwgts) { + for (l=0; l<ncon; l++) { + if (isfvwgts) { #ifdef __MSC__ - graph->fvwgts[i*ncon+l] = (float)strtod(head, &tail); + graph->fvwgts[i*ncon+l] = (float)strtod(head, &tail); #else - graph->fvwgts[i*ncon+l] = strtof(head, &tail); + graph->fvwgts[i*ncon+l] = strtof(head, &tail); #endif - if (tail == head) - gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights " - "for the %d constraints.\n", i+1, ncon); - if (graph->fvwgts[i*ncon+l] < 0) - gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l); + if (tail == head) + gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights " + "for the %d constraints.\n", i+1, ncon); + if (graph->fvwgts[i*ncon+l] < 0) + gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l); + } + else { + graph->ivwgts[i*ncon+l] = strtol(head, &tail, 0); + if (tail == head) + gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights " + "for the %d constraints.\n", i+1, ncon); + if (graph->ivwgts[i*ncon+l] < 0) + gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l); + } + head = tail; + } } - else { - graph->ivwgts[i*ncon+l] = strtol(head, &tail, 0); - if (tail == head) - gk_errexit(SIGERR, "The line for vertex %zd does not have enough weights " - "for the %d constraints.\n", i+1, ncon); - if (graph->ivwgts[i*ncon+l] < 0) - gk_errexit(SIGERR, "The weight vertex %zd and constraint %zd must be >= 0\n", i+1, l); + + + /* Read the rest of the row */ + while (1) { + ival = (int)strtol(head, &tail, 0); + if (tail == head) + break; + head = tail; + + if ((graph->adjncy[k] = ival + numbering) < 0) + gk_errexit(SIGERR, "Error: Invalid column number %d at row %zd.\n", ival, i); + + if (readvals) { + if (isfewgts) { +#ifdef __MSC__ + fval = (float)strtod(head, &tail); +#else + fval = strtof(head, &tail); +#endif + if (tail == head) + gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k); + + graph->fadjwgt[k] = fval; + } + else { + ival = strtol(head, &tail, 0); + if (tail == head) + gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k); + + graph->iadjwgt[k] = ival; + } + head = tail; + } + k++; } - head = tail; + graph->xadj[i+1] = k; } - } + + if (k != nedges) + gk_errexit(SIGERR, "gk_graph_Read: Something wrong with the number of edges in " + "the input file. nedges=%zd, Actualnedges=%zd.\n", nedges, k); + + gk_fclose(fpin); + + gk_free((void **)&line, LTERM); - - /* Read the rest of the row */ - while (1) { - ival = (int)strtol(head, &tail, 0); - if (tail == head) - break; - head = tail; - - if ((graph->adjncy[k] = ival + numbering) < 0) - gk_errexit(SIGERR, "Error: Invalid column number %d at row %zd.\n", ival, i); + break; - if (readvals) { - if (isfewgts) { -#ifdef __MSC__ - fval = (float)strtod(head, &tail); -#else - fval = strtof(head, &tail); -#endif - if (tail == head) - gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k); + case GK_GRAPH_FMT_IJV: + case GK_GRAPH_FMT_HIJV: + gk_getfilestats(filename, &nvtxs, &nedges, NULL, NULL); + + if (format == GK_GRAPH_FMT_HIJV) { /* remove the #rows/#cols values and row */ + nedges -= 2; + nvtxs -= 1; + } + + if (hasvals == 1 && 3*nvtxs != nedges) + gk_errexit(SIGERR, "Error: The number of numbers (%zd %d) in the input file is not a multiple of 3.\n", nedges, hasvals); + if (hasvals == 0 && 2*nvtxs != nedges) + gk_errexit(SIGERR, "Error: The number of numbers (%zd %d) in the input file is not a multiple of 2.\n", nedges, hasvals); + + nedges = nvtxs; + numbering = (numbering ? -1 : 0); + + /* read the data into three arrays */ + iinds = gk_i32malloc(nedges, "iinds"); + jinds = gk_i32malloc(nedges, "jinds"); + if (hasvals) { + if (isfewgts) + fvals = gk_fmalloc(nedges, "fvals"); + else + ivals = gk_i32malloc(nedges, "ivals"); + } + + fpin = gk_fopen(filename, "r", "gk_graph_Read: fpin"); + + if (format == GK_GRAPH_FMT_HIJV) { /* read and ignore the #rows/#cols values */ + if (fscanf(fpin, "%"SCNd64" %"SCNd64, &i, &i) != 2) + gk_errexit(SIGERR, "Error: Failed to read the header line.\n"); + } - graph->fadjwgt[k] = fval; + for (nvtxs=0, i=0; i<nedges; i++) { + if (hasvals) { + if (isfewgts) { + if (fscanf(fpin, "%"PRId32" %"PRId32" %f", &iinds[i], &jinds[i], &fvals[i]) != 3) + gk_errexit(SIGERR, "Error: Failed to read (i, j, val) for nedge: %zd.\n", i); + } + else { + if (fscanf(fpin, "%"PRId32" %"PRId32" %"PRId32, &iinds[i], &jinds[i], &ivals[i]) != 3) + gk_errexit(SIGERR, "Error: Failed to read (i, j, val) for nedge: %zd.\n", i); + } } else { - ival = strtol(head, &tail, 0); - if (tail == head) - gk_errexit(SIGERR, "Value could not be found for edge! Vertex:%zd, NNZ:%zd\n", i, k); - - graph->iadjwgt[k] = ival; + if (fscanf(fpin, "%"PRId32" %"PRId32, &iinds[i], &jinds[i]) != 2) + gk_errexit(SIGERR, "Error: Failed to read (i, j) value for nedge: %zd.\n", i); } - head = tail; + iinds[i] += numbering; + jinds[i] += numbering; + + if (nvtxs < iinds[i]) + nvtxs = iinds[i]; + if (nvtxs < jinds[i]) + nvtxs = jinds[i]; + } + gk_fclose(fpin); + + /* convert (i, j, v) into a graph format */ + graph = gk_graph_Create(); + graph->nvtxs = ++nvtxs; + xadj = graph->xadj = gk_zsmalloc(nvtxs+1, 0, "xadj"); + adjncy = graph->adjncy = gk_i32malloc(nedges, "adjncy"); + if (hasvals) { + if (isfewgts) + fadjwgt = graph->fadjwgt = gk_fmalloc(nedges, "fadjwgt"); + else + iadjwgt = graph->iadjwgt = gk_i32malloc(nedges, "iadjwgt"); } - k++; - } - graph->xadj[i+1] = k; - } - if (k != nedges) - gk_errexit(SIGERR, "gk_graph_Read: Something wrong with the number of edges in " - "the input file. nedges=%zd, Actualnedges=%zd.\n", nedges, k); + for (i=0; i<nedges; i++) + xadj[iinds[i]]++; + MAKECSR(i, nvtxs, xadj); + + for (i=0; i<nedges; i++) { + adjncy[xadj[iinds[i]]] = jinds[i]; + if (hasvals) { + if (isfewgts) + fadjwgt[xadj[iinds[i]]] = fvals[i]; + else + iadjwgt[xadj[iinds[i]]] = ivals[i]; + } + xadj[iinds[i]]++; + } + SHIFTCSR(i, nvtxs, xadj); - gk_fclose(fpin); + gk_free((void **)&iinds, &jinds, &fvals, &ivals, LTERM); + break; - gk_free((void **)&line, LTERM); + default: + gk_errexit(SIGERR, "Unrecognized format: %d\n", format); + } return graph; } @@ -270,19 +366,18 @@ gk_graph_t *gk_graph_Read(char *filename, int format, int isfewgts, /*! Writes a graph into a file. \param graph is the graph to be written, \param filename is the name of the output file. - \param format is one of GK_GRAPH_FMT_METIS specifying - the format of the output file. + \param format specifies the format of the output file. + \param numbering is either 0 or 1, indicating if the first vertex + will be numbered 0 or 1. Some formats ignore this. */ /**************************************************************************/ -void gk_graph_Write(gk_graph_t *graph, char *filename, int format) +void gk_graph_Write(gk_graph_t *graph, char *filename, int format, int numbering) { - ssize_t i, j; + int32_t i; + ssize_t j; int hasvwgts, hasvsizes, hasewgts; FILE *fpout; - if (format != GK_GRAPH_FMT_METIS) - gk_errexit(SIGERR, "Unknown file format. %d\n", format); - if (filename) fpout = gk_fopen(filename, "w", "gk_graph_Write: fpout"); else @@ -293,39 +388,64 @@ void gk_graph_Write(gk_graph_t *graph, char *filename, int format) hasvwgts = (graph->ivwgts || graph->fvwgts); hasvsizes = (graph->ivsizes || graph->fvsizes); - /* write the header line */ - fprintf(fpout, "%d %zd", graph->nvtxs, graph->xadj[graph->nvtxs]/2); - if (hasvwgts || hasvsizes || hasewgts) - fprintf(fpout, " %d%d%d", hasvsizes, hasvwgts, hasewgts); - fprintf(fpout, "\n"); - - - for (i=0; i<graph->nvtxs; i++) { - if (hasvsizes) { - if (graph->ivsizes) - fprintf(fpout, " %d", graph->ivsizes[i]); - else - fprintf(fpout, " %f", graph->fvsizes[i]); - } - - if (hasvwgts) { - if (graph->ivwgts) - fprintf(fpout, " %d", graph->ivwgts[i]); - else - fprintf(fpout, " %f", graph->fvwgts[i]); - } + switch (format) { + case GK_GRAPH_FMT_METIS: + /* write the header line */ + fprintf(fpout, "%d %zd", graph->nvtxs, graph->xadj[graph->nvtxs]/2); + if (hasvwgts || hasvsizes || hasewgts) + fprintf(fpout, " %d%d%d", hasvsizes, hasvwgts, hasewgts); + fprintf(fpout, "\n"); + + + for (i=0; i<graph->nvtxs; i++) { + if (hasvsizes) { + if (graph->ivsizes) + fprintf(fpout, " %d", graph->ivsizes[i]); + else + fprintf(fpout, " %f", graph->fvsizes[i]); + } + + if (hasvwgts) { + if (graph->ivwgts) + fprintf(fpout, " %d", graph->ivwgts[i]); + else + fprintf(fpout, " %f", graph->fvwgts[i]); + } + + for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) { + fprintf(fpout, " %d", graph->adjncy[j]+1); + if (hasewgts) { + if (graph->iadjwgt) + fprintf(fpout, " %d", graph->iadjwgt[j]); + else + fprintf(fpout, " %f", graph->fadjwgt[j]); + } + } + fprintf(fpout, "\n"); + } + break; - for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) { - fprintf(fpout, " %d", graph->adjncy[j]+1); - if (hasewgts) { - if (graph->iadjwgt) - fprintf(fpout, " %d", graph->iadjwgt[j]); - else - fprintf(fpout, " %f", graph->fadjwgt[j]); + case GK_GRAPH_FMT_IJV: + for (i=0; i<graph->nvtxs; i++) { + for (j=graph->xadj[i]; j<graph->xadj[i+1]; j++) { + fprintf(fpout, "%d %d ", i+numbering, graph->adjncy[j]+numbering); + if (hasewgts) { + if (graph->iadjwgt) + fprintf(fpout, " %d\n", graph->iadjwgt[j]); + else + fprintf(fpout, " %f\n", graph->fadjwgt[j]); + } + else { + fprintf(fpout, " 1\n"); + } + } } - } - fprintf(fpout, "\n"); + break; + + default: + gk_errexit(SIGERR, "Unknown file format. %d\n", format); } + if (filename) gk_fclose(fpout); } @@ -380,6 +500,71 @@ gk_graph_t *gk_graph_Dup(gk_graph_t *graph) } +/*************************************************************************/ +/*! Returns the transpose of a graph. + \param graph is the graph to be transposed. + \returns the newly created copy of the graph. +*/ +/**************************************************************************/ +gk_graph_t *gk_graph_Transpose(gk_graph_t *graph) +{ + int32_t vi, vj; + ssize_t ei; + + gk_graph_t *ngraph; + + ngraph = gk_graph_Create(); + + ngraph->nvtxs = graph->nvtxs; + ngraph->xadj = gk_zsmalloc(graph->nvtxs+1, 0, "gk_graph_Transpose: xadj"); + ngraph->adjncy = gk_i32malloc(graph->xadj[graph->nvtxs], "gk_graph_Transpose: adjncy"); + + if (graph->iadjwgt) + ngraph->iadjwgt = gk_i32malloc(graph->xadj[graph->nvtxs], "gk_graph_Transpose: iadjwgt"); + if (graph->fadjwgt) + ngraph->fadjwgt = gk_fmalloc(graph->xadj[graph->nvtxs], "gk_graph_Transpose: fadjwgt"); + + for (vi=0; vi<graph->nvtxs; vi++) { + for (ei=graph->xadj[vi]; ei<graph->xadj[vi+1]; ei++) + ngraph->xadj[graph->adjncy[ei]]++; + } + MAKECSR(vi, ngraph->nvtxs, ngraph->xadj); + + for (vi=0; vi<graph->nvtxs; vi++) { + for (ei=graph->xadj[vi]; ei<graph->xadj[vi+1]; ei++) { + vj = graph->adjncy[ei]; + ngraph->adjncy[ngraph->xadj[vj]] = vi; + if (ngraph->iadjwgt) + ngraph->iadjwgt[ngraph->xadj[vj]] = graph->iadjwgt[ei]; + if (ngraph->fadjwgt) + ngraph->fadjwgt[ngraph->xadj[vj]] = graph->fadjwgt[ei]; + ngraph->xadj[vj]++; + } + } + SHIFTCSR(vi, ngraph->nvtxs, ngraph->xadj); + + /* copy vertex attributes */ + if (graph->ivwgts) + ngraph->ivwgts = gk_i32copy(graph->nvtxs, graph->ivwgts, + gk_i32malloc(graph->nvtxs, "gk_graph_Transpose: ivwgts")); + if (graph->ivsizes) + ngraph->ivsizes = gk_i32copy(graph->nvtxs, graph->ivsizes, + gk_i32malloc(graph->nvtxs, "gk_graph_Transpose: ivsizes")); + if (graph->vlabels) + ngraph->vlabels = gk_i32copy(graph->nvtxs, graph->vlabels, + gk_i32malloc(graph->nvtxs, "gk_graph_Transpose: ivlabels")); + if (graph->fvwgts) + ngraph->fvwgts = gk_fcopy(graph->nvtxs, graph->fvwgts, + gk_fmalloc(graph->nvtxs, "gk_graph_Transpose: fvwgts")); + if (graph->fvsizes) + ngraph->fvsizes = gk_fcopy(graph->nvtxs, graph->fvsizes, + gk_fmalloc(graph->nvtxs, "gk_graph_Transpose: fvsizes")); + + + return ngraph; +} + + /*************************************************************************/ /*! Returns a subgraph containing a set of consecutive vertices. \param graph is the original graph. @@ -574,7 +759,7 @@ int gk_graph_FindComponents(gk_graph_t *graph, int32_t *cptr, int32_t *cind) ssize_t i, ii, j, jj, k, nvtxs, first, last, ntodo, ncmps; ssize_t *xadj; int32_t *adjncy, *pos, *todo; - int32_t mustfree_ccsr=0, mustfree_where=0; + int32_t mustfree_ccsr=0; nvtxs = graph->nvtxs; xadj = graph->xadj; @@ -603,36 +788,42 @@ int gk_graph_FindComponents(gk_graph_t *graph, int32_t *cptr, int32_t *cind) first = last = 0; /* Point to the first and last vertices that have been touched but not explored. These vertices are stored in cind[first]...cind[last-1]. */ - while (ntodo > 0) { + while (1) { if (first == last) { /* Find another starting vertex */ cptr[++ncmps] = first; /* Mark the end of the current CC */ - ASSERT(pos[todo[0]] != -1); - i = todo[0]; + if (ntodo > 0) { + /* put the first vertex in the todo list as the start of the new CC */ + GKASSERT(pos[todo[0]] != -1); + cind[last++] = todo[0]; - cind[last++] = i; - pos[i] = -1; + pos[todo[0]] = -1; + todo[0] = todo[--ntodo]; + pos[todo[0]] = 0; + } + else { + break; + } } i = cind[first++]; /* Get the first visited but unexplored vertex */ - /* Remove i from the todo list and put the last item in the todo - list at the position that i was so that the todo list will be - consequtive. The pos[] array is updated accordingly to keep track - the location of the vertices in the todo[] list. */ - k = pos[i]; - j = todo[k] = todo[--ntodo]; - pos[j] = k; - for (j=xadj[i]; j<xadj[i+1]; j++) { k = adjncy[j]; if (pos[k] != -1) { cind[last++] = k; + + /* Remove k from the todo list and put the last item in the todo + list at the position that k was so that the todo list will be + consequtive. The pos[] array is updated accordingly to keep track + the location of the vertices in the todo[] list. */ + todo[pos[k]] = todo[--ntodo]; + pos[todo[pos[k]]] = pos[k]; pos[k] = -1; } } } - cptr[++ncmps] = first; + GKASSERT(first == nvtxs); if (mustfree_ccsr) gk_free((void **)&cptr, &cind, LTERM); @@ -690,7 +881,7 @@ void gk_graph_ComputeBFSOrdering(gk_graph_t *graph, int v, int32_t **r_perm, pos[0] = cot[0] = v; pos[v] = cot[v] = 0; - /* Find the connected componends induced by the partition */ + /* compute a BFS ordering from the seed vertex */ first = last = 0; while (first < nvtxs) { if (first == last) { /* Find another starting vertex */ @@ -703,9 +894,9 @@ void gk_graph_ComputeBFSOrdering(gk_graph_t *graph, int v, int32_t **r_perm, i = cot[first++]; /* the ++ advances the explored vertices */ for (j=xadj[i]; j<xadj[i+1]; j++) { k = adjncy[j]; - /* if a node has already been visited, its perm[] will be -1 */ + /* if a node has already been visited, its pos[] will be -1 */ if (pos[k] != -1) { - /* pos[k] is the location within iperm of where k resides (it is in the 'todo' part); + /* pos[k] is the location within cot[] where k resides (it is in the 'todo' part); It is placed in that location cot[last] (end of OPEN list) that we are about to overwrite and update pos[cot[last]] to reflect that. */ cot[pos[k]] = cot[last]; /* put the head of the todo list to @@ -889,7 +1080,8 @@ void gk_graph_ComputeBestFOrdering(gk_graph_t *graph, int v, int type, { ssize_t j, jj, *xadj; int i, k, u, nvtxs, nopen, ntodo; - int32_t *adjncy, *perm, *degrees, *wdegrees, *sod, *level, *ot, *pos; + int32_t *adjncy, *perm, *degrees, *sod, *level, *ot, *pos; + int64_t *wdegrees; gk_i32pq_t *queue; if (graph->nvtxs <= 0) @@ -903,7 +1095,7 @@ void gk_graph_ComputeBestFOrdering(gk_graph_t *graph, int v, int type, degrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: degrees"); /* the weighted degree of the vertices in the closed list for type==3 */ - wdegrees = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: wdegrees"); + wdegrees = gk_i64smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: wdegrees"); /* the sum of differences for type==4 */ sod = gk_i32smalloc(nvtxs, 0, "gk_graph_ComputeBestFOrdering: sod"); @@ -994,7 +1186,7 @@ void gk_graph_ComputeBestFOrdering(gk_graph_t *graph, int v, int type, case 3: /* Sum of orders in closed list */ wdegrees[u] += i; - gk_i32pqUpdate(queue, u, wdegrees[u]); + gk_i32pqUpdate(queue, u, (int32_t)sqrt(wdegrees[u])); break; case 4: /* Sum of order-differences */ @@ -1185,9 +1377,6 @@ void gk_graph_SingleSourceShortestPaths(gk_graph_t *graph, int v, void **r_sps) } - -#ifdef XXX - /*************************************************************************/ /*! Sorts the adjacency lists in increasing vertex order \param graph the graph itself, @@ -1195,74 +1384,251 @@ void gk_graph_SingleSourceShortestPaths(gk_graph_t *graph, int v, void **r_sps) /**************************************************************************/ void gk_graph_SortAdjacencies(gk_graph_t *graph) { - int n, nn=0; - ssize_t *ptr; - int *ind; - float *val; - - switch (what) { - case GK_CSR_ROW: - if (!graph->rowptr) - gk_errexit(SIGERR, "Row-based view of the graphrix does not exists.\n"); - - n = graph->nrows; - ptr = graph->rowptr; - ind = graph->rowind; - val = graph->rowval; - break; - - case GK_CSR_COL: - if (!graph->colptr) - gk_errexit(SIGERR, "Column-based view of the graphrix does not exists.\n"); + int32_t nvtxs, nn=0; + ssize_t *xadj; + int32_t *adjncy; + int32_t *iadjwgt; + float *fadjwgt; - n = graph->ncols; - ptr = graph->colptr; - ind = graph->colind; - val = graph->colval; - break; + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + iadjwgt = graph->iadjwgt; + fadjwgt = graph->fadjwgt; - default: - gk_errexit(SIGERR, "Invalid index type of %d.\n", what); - return; - } - - #pragma omp parallel if (n > 100) + #pragma omp parallel if (nvtxs > 100) { ssize_t i, j, k; gk_ikv_t *cand; - float *tval; + int32_t *itwgts=NULL; + float *ftwgts=NULL; #pragma omp single - for (i=0; i<n; i++) - nn = gk_max(nn, ptr[i+1]-ptr[i]); + for (i=0; i<nvtxs; i++) + nn = gk_max(nn, xadj[i+1]-xadj[i]); - cand = gk_ikvmalloc(nn, "gk_graph_SortIndices: cand"); - tval = gk_fmalloc(nn, "gk_graph_SortIndices: tval"); + cand = gk_ikvmalloc(nn, "gk_graph_SortIndices: cand"); + if (iadjwgt) + itwgts = gk_i32malloc(nn, "gk_graph_SortIndices: itwgts"); + if (fadjwgt) + ftwgts = gk_fmalloc(nn, "gk_graph_SortIndices: ftwgts"); #pragma omp for schedule(static) - for (i=0; i<n; i++) { - for (k=0, j=ptr[i]; j<ptr[i+1]; j++) { - if (j > ptr[i] && ind[j] < ind[j-1]) + for (i=0; i<nvtxs; i++) { + for (k=0, j=xadj[i]; j<xadj[i+1]; j++) { + if (j > xadj[i] && adjncy[j] < adjncy[j-1]) k = 1; /* an inversion */ - cand[j-ptr[i]].val = j-ptr[i]; - cand[j-ptr[i]].key = ind[j]; - tval[j-ptr[i]] = val[j]; + cand[j-xadj[i]].val = (int32_t)(j-xadj[i]); + cand[j-xadj[i]].key = adjncy[j]; + if (itwgts) + itwgts[j-xadj[i]] = iadjwgt[j]; + if (ftwgts) + ftwgts[j-xadj[i]] = fadjwgt[j]; } if (k) { - gk_ikvsorti(ptr[i+1]-ptr[i], cand); - for (j=ptr[i]; j<ptr[i+1]; j++) { - ind[j] = cand[j-ptr[i]].key; - val[j] = tval[cand[j-ptr[i]].val]; + gk_ikvsorti(xadj[i+1]-xadj[i], cand); + for (j=xadj[i]; j<xadj[i+1]; j++) { + adjncy[j] = cand[j-xadj[i]].key; + if (itwgts) + iadjwgt[j] = itwgts[cand[j-xadj[i]].val]; + if (ftwgts) + fadjwgt[j] = ftwgts[cand[j-xadj[i]].val]; + } + } + } + + gk_free((void **)&cand, &itwgts, &ftwgts, LTERM); + } +} + + +/*************************************************************************/ +/*! Returns a symmetric version of a graph. The symmetric version + is constructed by applying an A op A^T operation, where op is one of + GK_GRAPH_SYM_SUM, GK_GRAPH_SYM_MIN, GK_GRAPH_SYM_MAX, GK_GRAPH_SYM_AVG. + + \param mat the matrix to be symmetrized, + \param op indicates the operation to be performed. The possible values are + GK_GRAPH_SYM_SUM, GK_GRAPH_SYM_MIN, GK_GRAPH_SYM_MAX, and GK_GRAPH_SYM_AVG. + + \returns the symmetrized matrix consisting only of its row-based structure. + The input matrix is not modified. + +TODO: Need to deal with all vertex attributes that are currently do not get + copied over. +*/ +/**************************************************************************/ +gk_graph_t *gk_graph_MakeSymmetric(gk_graph_t *graph, int op) +{ + ssize_t i, j, k, nnz; + int nrows, nadj, hasvals; + ssize_t *rowptr, *colptr, *nrowptr; + int *rowind, *colind, *nrowind, *marker, *ids; + float *rowval=NULL, *colval=NULL, *nrowval=NULL, *wgts=NULL; + int32_t *irowval=NULL, *icolval=NULL, *nirowval=NULL, *iwgts=NULL; + gk_graph_t *ngraph; + + hasvals = (graph->iadjwgt != NULL || graph->fadjwgt != NULL); + + nrows = graph->nvtxs; + rowptr = graph->xadj; + rowind = graph->adjncy; + if (hasvals) { + irowval = graph->iadjwgt; + rowval = graph->fadjwgt; + } + + /* create the column view for efficient processing */ + colptr = gk_zsmalloc(nrows+1, 0, "colptr"); + colind = gk_i32malloc(rowptr[nrows], "colind"); + if (hasvals) { + if (rowval) + colval = gk_fmalloc(rowptr[nrows], "colval"); + if (irowval) + icolval = gk_i32malloc(rowptr[nrows], "icolval"); + } + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + colptr[rowind[j]]++; + } + MAKECSR(i, nrows, colptr); + + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + colind[colptr[rowind[j]]] = i; + if (hasvals) { + if (rowval) + colval[colptr[rowind[j]]] = rowval[j]; + if (irowval) + icolval[colptr[rowind[j]]] = irowval[j]; + } + colptr[rowind[j]]++; + } + } + SHIFTCSR(i, nrows, colptr); + + + ngraph = gk_graph_Create(); + ngraph->nvtxs = graph->nvtxs; + + nrowptr = ngraph->xadj = gk_zmalloc(nrows+1, "gk_csr_MakeSymmetric: nrowptr"); + nrowind = ngraph->adjncy = gk_imalloc(2*rowptr[nrows], "gk_csr_MakeSymmetric: nrowind"); + if (hasvals) { + if (rowval) + nrowval = graph->fadjwgt = gk_fmalloc(2*rowptr[nrows], "gk_csr_MakeSymmetric: nrowval"); + if (irowval) + nirowval = graph->iadjwgt = gk_i32malloc(2*rowptr[nrows], "gk_csr_MakeSymmetric: nrowval"); + } + + marker = gk_ismalloc(nrows, -1, "marker"); + ids = gk_imalloc(nrows, "ids"); + if (hasvals) { + if (rowval) + wgts = gk_fmalloc(nrows, "wgts"); + if (irowval) + iwgts = gk_i32malloc(nrows, "wgts"); + } + + nrowptr[0] = nnz = 0; + for (i=0; i<nrows; i++) { + nadj = 0; + /* out-edges */ + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + ids[nadj] = rowind[j]; + if (wgts) + wgts[nadj] = (op == GK_CSR_SYM_AVG ? 0.5*rowval[j] : rowval[j]); + if (iwgts) + iwgts[nadj] = (op == GK_CSR_SYM_AVG ? 0.5*irowval[j] : irowval[j]); + marker[rowind[j]] = nadj++; + } + + /* in-edges */ + for (j=colptr[i]; j<colptr[i+1]; j++) { + if (marker[colind[j]] == -1) { + if (op != GK_CSR_SYM_MIN) { + ids[nadj] = colind[j]; + if (wgts) + wgts[nadj] = (op == GK_CSR_SYM_AVG ? 0.5*colval[j] : colval[j]); + if (iwgts) + iwgts[nadj] = (op == GK_CSR_SYM_AVG ? 0.5*icolval[j] : icolval[j]); + nadj++; + } + } + else { + if (wgts) { + switch (op) { + case GK_CSR_SYM_MAX: + wgts[marker[colind[j]]] = gk_max(colval[j], wgts[marker[colind[j]]]); + break; + case GK_CSR_SYM_MIN: + wgts[marker[colind[j]]] = gk_min(colval[j], wgts[marker[colind[j]]]); + break; + case GK_CSR_SYM_SUM: + wgts[marker[colind[j]]] += colval[j]; + break; + case GK_CSR_SYM_AVG: + wgts[marker[colind[j]]] = 0.5*(wgts[marker[colind[j]]] + colval[j]); + break; + default: + errexit("Unsupported op for MakeSymmetric!\n"); + } } + if (iwgts) { + switch (op) { + case GK_CSR_SYM_MAX: + iwgts[marker[colind[j]]] = gk_max(icolval[j], iwgts[marker[colind[j]]]); + break; + case GK_CSR_SYM_MIN: + iwgts[marker[colind[j]]] = gk_min(icolval[j], iwgts[marker[colind[j]]]); + break; + case GK_CSR_SYM_SUM: + iwgts[marker[colind[j]]] += icolval[j]; + break; + case GK_CSR_SYM_AVG: + iwgts[marker[colind[j]]] = 0.5*(wgts[marker[colind[j]]] + icolval[j]); + break; + default: + errexit("Unsupported op for MakeSymmetric!\n"); + } + } + marker[colind[j]] = -1; } } - gk_free((void **)&cand, &tval, LTERM); + /* go over out edges again to resolve any edges that were not found in the in + * edges */ + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + if (marker[rowind[j]] != -1) { + if (op == GK_CSR_SYM_MIN) + ids[marker[rowind[j]]] = -1; + marker[rowind[j]] = -1; + } + } + + /* put the non '-1' entries in ids[] into i's row */ + for (j=0; j<nadj; j++) { + if (ids[j] != -1) { + nrowind[nnz] = ids[j]; + if (wgts) + nrowval[nnz] = wgts[j]; + if (iwgts) + nirowval[nnz] = iwgts[j]; + nnz++; + } + } + nrowptr[i+1] = nnz; } + gk_free((void **)&colptr, &colind, &colval, &icolval, &marker, &ids, &wgts, &iwgts, LTERM); + + return ngraph; } + +#ifdef XXX + /*************************************************************************/ /*! Returns a subgraphrix containing a certain set of rows. \param graph is the original graphrix. diff --git a/3rdParty/metis/metis-5.1.0/GKlib/htable.c b/3rdParty/metis/metis-5.1.1/GKlib/htable.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/htable.c rename to 3rdParty/metis/metis-5.1.1/GKlib/htable.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/io.c b/3rdParty/metis/metis-5.1.1/GKlib/io.c similarity index 57% rename from 3rdParty/metis/metis-5.1.0/GKlib/io.c rename to 3rdParty/metis/metis-5.1.1/GKlib/io.c index caaedcb59c03357013435a871815c0712e9a9b53..a15648356e4258e570f6c8a888a7e5c68e201bfe 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/io.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/io.c @@ -6,7 +6,7 @@ This file contains various functions that perform I/O. \date Started 4/10/95 \author George -\version\verbatim $Id: io.c 12591 2012-09-01 19:03:15Z karypis $ \endverbatim +\version\verbatim $Id: io.c 18951 2015-08-08 20:10:46Z karypis $ \endverbatim */ #ifdef HAVE_GETLINE @@ -47,6 +47,52 @@ void gk_fclose(FILE *fp) } +/*************************************************************************/ +/*! This function is a wrapper around the read() function that ensures + that all data is been read, by issuing multiple read requests. + The only time when not 'count' items are read is when the EOF has been + reached. +*/ +/*************************************************************************/ +ssize_t gk_read(int fd, void *vbuf, size_t count) +{ + char *buf = (char *)vbuf; + ssize_t rsize, tsize=count; + + do { + if ((rsize = read(fd, buf, tsize)) == -1) + return -1; + buf += rsize; + tsize -= rsize; + } while (tsize > 0 && rsize > 0); + + return count-tsize; +} + + +/*************************************************************************/ +/*! This function is a wrapper around the write() function that ensures + that all data is been written, by issueing multiple write requests. +*/ +/*************************************************************************/ +ssize_t gk_write(int fd, void *vbuf, size_t count) +{ + char *buf = (char *)vbuf; + ssize_t size, tsize=count; + + do { + if ((size = write(fd, buf, tsize)) == -1) + return -1; + buf += size; + tsize -= size; + } while (tsize > 0); + + return count; +} + + + + /*************************************************************************/ /*! This function is the GKlib implementation of glibc's getline() function. @@ -100,9 +146,9 @@ gk_idx_t gk_getline(char **lineptr, size_t *n, FILE *stream) this information is not returned. */ /*************************************************************************/ -char **gk_readfile(char *fname, gk_idx_t *r_nlines) +char **gk_readfile(char *fname, size_t *r_nlines) { - size_t lnlen, nlines; + size_t lnlen, nlines=0; char *line=NULL, **lines=NULL; FILE *fpin; @@ -127,7 +173,6 @@ char **gk_readfile(char *fname, gk_idx_t *r_nlines) return lines; } - /*************************************************************************/ /*! This function reads the contents of a file and returns it in the form of an array of int32_t. @@ -136,9 +181,9 @@ char **gk_readfile(char *fname, gk_idx_t *r_nlines) this information is not returned. */ /*************************************************************************/ -int32_t *gk_i32readfile(char *fname, gk_idx_t *r_nlines) +int32_t *gk_i32readfile(char *fname, size_t *r_nlines) { - size_t lnlen, nlines; + size_t lnlen, nlines=0; char *line=NULL; int32_t *array=NULL; FILE *fpin; @@ -165,7 +210,6 @@ int32_t *gk_i32readfile(char *fname, gk_idx_t *r_nlines) return array; } - /*************************************************************************/ /*! This function reads the contents of a file and returns it in the form of an array of int64_t. @@ -174,9 +218,9 @@ int32_t *gk_i32readfile(char *fname, gk_idx_t *r_nlines) this information is not returned. */ /*************************************************************************/ -int64_t *gk_i64readfile(char *fname, gk_idx_t *r_nlines) +int64_t *gk_i64readfile(char *fname, size_t *r_nlines) { - size_t lnlen, nlines; + size_t lnlen, nlines=0; char *line=NULL; int64_t *array=NULL; FILE *fpin; @@ -203,6 +247,43 @@ int64_t *gk_i64readfile(char *fname, gk_idx_t *r_nlines) return array; } +/*************************************************************************/ +/*! This function reads the contents of a file and returns it in the + form of an array of ssize_t. + \param fname is the name of the file + \param r_nlines is the number of lines in the file. If it is NULL, + this information is not returned. +*/ +/*************************************************************************/ +ssize_t *gk_zreadfile(char *fname, size_t *r_nlines) +{ + size_t lnlen, nlines=0; + char *line=NULL; + ssize_t *array=NULL; + FILE *fpin; + + gk_getfilestats(fname, &nlines, NULL, NULL, NULL); + if (nlines > 0) { + array = gk_zmalloc(nlines, "gk_zreadfile: array"); + + fpin = gk_fopen(fname, "r", "gk_readfile"); + nlines = 0; + + while (gk_getline(&line, &lnlen, fpin) != -1) { + sscanf(line, "%zd", &array[nlines++]); + } + + gk_fclose(fpin); + } + + gk_free((void **)&line, LTERM); + + if (r_nlines != NULL) + *r_nlines = nlines; + + return array; +} + /*************************************************************************/ /*! This function reads the contents of a binary file and returns it in the form of an array of int32_t. @@ -211,17 +292,24 @@ int64_t *gk_i64readfile(char *fname, gk_idx_t *r_nlines) this information is not returned. */ /*************************************************************************/ -int32_t *gk_i32readfilebin(char *fname, ssize_t *r_nelmnts) +int32_t *gk_i32readfilebin(char *fname, size_t *r_nelmnts) { - ssize_t fsize, nelmnts; + size_t nelmnts; + ssize_t fsize; int32_t *array=NULL; FILE *fpin; - *r_nelmnts = -1; + *r_nelmnts = 0; + + fsize = gk_getfsize(fname); + + if (fsize == -1) { + gk_errexit(SIGERR, "Failed to fstat(%s).\n", fname); + return NULL; + } - fsize = (ssize_t) gk_getfsize(fname); if (fsize%sizeof(int32_t) != 0) { - gk_errexit(SIGERR, "The size of the file is not in multiples of sizeof(int32_t).\n"); + gk_errexit(SIGERR, "The size [%zd] of the file [%s] is not in multiples of sizeof(int32_t).\n", fsize, fname); return NULL; } @@ -242,6 +330,27 @@ int32_t *gk_i32readfilebin(char *fname, ssize_t *r_nelmnts) return array; } +/*************************************************************************/ +/*! This function writes the contents of an array into a binary file. + \param fname is the name of the file + \param n the number of elements in the array. + \param a the array to be written out. +*/ +/*************************************************************************/ +size_t gk_i32writefilebin(char *fname, size_t n, int32_t *a) +{ + size_t fsize; + FILE *fp; + + fp = gk_fopen(fname, "wb", "gk_writefilebin"); + + fsize = fwrite(a, sizeof(int32_t), n, fp); + + gk_fclose(fp); + + return fsize; +} + /*************************************************************************/ /*! This function reads the contents of a binary file and returns it in the form of an array of int64_t. @@ -250,15 +359,22 @@ int32_t *gk_i32readfilebin(char *fname, ssize_t *r_nelmnts) this information is not returned. */ /*************************************************************************/ -int64_t *gk_i64readfilebin(char *fname, ssize_t *r_nelmnts) +int64_t *gk_i64readfilebin(char *fname, size_t *r_nelmnts) { - ssize_t fsize, nelmnts; + size_t nelmnts; + ssize_t fsize; int64_t *array=NULL; FILE *fpin; - *r_nelmnts = -1; + *r_nelmnts = 0; + + fsize = gk_getfsize(fname); + + if (fsize == -1) { + gk_errexit(SIGERR, "Failed to fstat(%s).\n", fname); + return NULL; + } - fsize = (ssize_t) gk_getfsize(fname); if (fsize%sizeof(int64_t) != 0) { gk_errexit(SIGERR, "The size of the file is not in multiples of sizeof(int64_t).\n"); return NULL; @@ -281,6 +397,94 @@ int64_t *gk_i64readfilebin(char *fname, ssize_t *r_nelmnts) return array; } +/*************************************************************************/ +/*! This function writes the contents of an array into a binary file. + \param fname is the name of the file + \param n the number of elements in the array. + \param a the array to be written out. +*/ +/*************************************************************************/ +size_t gk_i64writefilebin(char *fname, size_t n, int64_t *a) +{ + size_t fsize; + FILE *fp; + + fp = gk_fopen(fname, "wb", "gk_writefilebin"); + + fsize = fwrite(a, sizeof(int64_t), n, fp); + + gk_fclose(fp); + + return fsize; +} + +/*************************************************************************/ +/*! This function reads the contents of a binary file and returns it in the + form of an array of ssize_t. + \param fname is the name of the file + \param r_nlines is the number of lines in the file. If it is NULL, + this information is not returned. +*/ +/*************************************************************************/ +ssize_t *gk_zreadfilebin(char *fname, size_t *r_nelmnts) +{ + size_t nelmnts; + ssize_t fsize; + ssize_t *array=NULL; + FILE *fpin; + + *r_nelmnts = 0; + + fsize = gk_getfsize(fname); + + if (fsize == -1) { + gk_errexit(SIGERR, "Failed to fstat(%s).\n", fname); + return NULL; + } + + if (fsize%sizeof(ssize_t) != 0) { + gk_errexit(SIGERR, "The size of the file is not in multiples of sizeof(ssize_t).\n"); + return NULL; + } + + nelmnts = fsize/sizeof(ssize_t); + array = gk_zmalloc(nelmnts, "gk_zreadfilebin: array"); + + fpin = gk_fopen(fname, "rb", "gk_zreadfilebin"); + + if (fread(array, sizeof(ssize_t), nelmnts, fpin) != nelmnts) { + gk_errexit(SIGERR, "Failed to read the number of words requested. %zd\n", nelmnts); + gk_free((void **)&array, LTERM); + return NULL; + } + gk_fclose(fpin); + + *r_nelmnts = nelmnts; + + return array; +} + +/*************************************************************************/ +/*! This function writes the contents of an array into a binary file. + \param fname is the name of the file + \param n the number of elements in the array. + \param a the array to be written out. +*/ +/*************************************************************************/ +size_t gk_zwritefilebin(char *fname, size_t n, ssize_t *a) +{ + size_t fsize; + FILE *fp; + + fp = gk_fopen(fname, "wb", "gk_writefilebin"); + + fsize = fwrite(a, sizeof(ssize_t), n, fp); + + gk_fclose(fp); + + return fsize; +} + /*************************************************************************/ /*! This function reads the contents of a binary file and returns it in the form of an array of float. @@ -289,15 +493,22 @@ int64_t *gk_i64readfilebin(char *fname, ssize_t *r_nelmnts) this information is not returned. */ /*************************************************************************/ -float *gk_freadfilebin(char *fname, ssize_t *r_nelmnts) +float *gk_freadfilebin(char *fname, size_t *r_nelmnts) { - ssize_t fsize, nelmnts; + size_t nelmnts; + ssize_t fsize; float *array=NULL; FILE *fpin; - *r_nelmnts = -1; + *r_nelmnts = 0; + + fsize = gk_getfsize(fname); + + if (fsize == -1) { + gk_errexit(SIGERR, "Failed to fstat(%s).\n", fname); + return NULL; + } - fsize = (ssize_t) gk_getfsize(fname); if (fsize%sizeof(float) != 0) { gk_errexit(SIGERR, "The size of the file is not in multiples of sizeof(float).\n"); return NULL; @@ -320,7 +531,6 @@ float *gk_freadfilebin(char *fname, ssize_t *r_nelmnts) return array; } - /*************************************************************************/ /*! This function writes the contents of an array into a binary file. \param fname is the name of the file @@ -342,7 +552,6 @@ size_t gk_fwritefilebin(char *fname, size_t n, float *a) return fsize; } - /*************************************************************************/ /*! This function reads the contents of a binary file and returns it in the form of an array of double. @@ -351,15 +560,22 @@ size_t gk_fwritefilebin(char *fname, size_t n, float *a) this information is not returned. */ /*************************************************************************/ -double *gk_dreadfilebin(char *fname, ssize_t *r_nelmnts) +double *gk_dreadfilebin(char *fname, size_t *r_nelmnts) { - ssize_t fsize, nelmnts; + size_t nelmnts; + ssize_t fsize; double *array=NULL; FILE *fpin; - *r_nelmnts = -1; + *r_nelmnts = 0; + + fsize = gk_getfsize(fname); + + if (fsize == -1) { + gk_errexit(SIGERR, "Failed to fstat(%s).\n", fname); + return NULL; + } - fsize = (ssize_t) gk_getfsize(fname); if (fsize%sizeof(double) != 0) { gk_errexit(SIGERR, "The size of the file is not in multiples of sizeof(double).\n"); return NULL; @@ -382,3 +598,24 @@ double *gk_dreadfilebin(char *fname, ssize_t *r_nelmnts) return array; } +/*************************************************************************/ +/*! This function writes the contents of an array into a binary file. + \param fname is the name of the file + \param n the number of elements in the array. + \param a the array to be written out. +*/ +/*************************************************************************/ +size_t gk_dwritefilebin(char *fname, size_t n, double *a) +{ + size_t fsize; + FILE *fp; + + fp = gk_fopen(fname, "wb", "gk_writefilebin"); + + fsize = fwrite(a, sizeof(double), n, fp); + + gk_fclose(fp); + + return fsize; +} + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/itemsets.c b/3rdParty/metis/metis-5.1.1/GKlib/itemsets.c similarity index 96% rename from 3rdParty/metis/metis-5.1.0/GKlib/itemsets.c rename to 3rdParty/metis/metis-5.1.1/GKlib/itemsets.c index 65b5af40d0f1df524776cc3d1523522096168d1a..beb58aea57a98eaf818086a3a8cf48108bcd1104 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/itemsets.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/itemsets.c @@ -7,7 +7,7 @@ * * \date 6/13/2008 * \author George Karypis - * \version\verbatim $Id: itemsets.c 11075 2011-11-11 22:31:52Z karypis $ \endverbatim + * \version\verbatim $Id: itemsets.c 19240 2015-10-22 12:41:19Z karypis $ \endverbatim */ #include <GKlib.h> @@ -58,7 +58,7 @@ void gk_find_frequent_itemsets(int ntrans, ssize_t *tranptr, int *tranind, /* Create the matrix */ mat = gk_csr_Create(); mat->nrows = ntrans; - mat->ncols = tranind[gk_iargmax(tranptr[ntrans], tranind)]+1; + mat->ncols = tranind[gk_iargmax(tranptr[ntrans], tranind, 1)]+1; mat->rowptr = gk_zcopy(ntrans+1, tranptr, gk_zmalloc(ntrans+1, "gk_find_frequent_itemsets: mat.rowptr")); mat->rowind = gk_icopy(tranptr[ntrans], tranind, gk_imalloc(tranptr[ntrans], "gk_find_frequent_itemsets: mat.rowind")); mat->colids = gk_iincset(mat->ncols, 0, gk_imalloc(mat->ncols, "gk_find_frequent_itemsets: mat.colids")); @@ -119,10 +119,10 @@ void itemsets_find_frequent_itemsets(isparams_t *params, gk_csr_t *mat, /******************************************************************************/ /*! This function projects a matrix w.r.t. to a particular column. It performs the following steps: - - Determines the length of each column that is remaining - - Sorts the columns in increasing length + - Determines the length of each column that is remaining. + - Sorts the columns in increasing length. - Creates a column-based version of the matrix with the proper - column ordering and renamed rowids. + column ordering. */ /*******************************************************************************/ gk_csr_t *itemsets_project_matrix(isparams_t *params, gk_csr_t *mat, int cid) diff --git a/3rdParty/metis/metis-5.1.0/GKlib/mcore.c b/3rdParty/metis/metis-5.1.1/GKlib/mcore.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/mcore.c rename to 3rdParty/metis/metis-5.1.1/GKlib/mcore.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/memory.c b/3rdParty/metis/metis-5.1.1/GKlib/memory.c similarity index 82% rename from 3rdParty/metis/metis-5.1.0/GKlib/memory.c rename to 3rdParty/metis/metis-5.1.1/GKlib/memory.c index cdd00fa79ab02fcbd0eedb32f9bef303ff339f29..59c6d5a3a61e5be238a1307f3c792903fabe339d 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/memory.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/memory.c @@ -9,7 +9,7 @@ can be used to define other memory allocation routines. \date Started 4/3/2007 \author George -\version\verbatim $Id: memory.c 10783 2011-09-21 23:19:56Z karypis $ \endverbatim +\version\verbatim $Id: memory.c 21050 2017-05-25 03:53:58Z karypis $ \endverbatim */ @@ -22,20 +22,30 @@ static __thread gk_mcore_t *gkmcore = NULL; /*************************************************************************/ /*! Define the set of memory allocation routines for each data type */ /**************************************************************************/ -GK_MKALLOC(gk_c, char) -GK_MKALLOC(gk_i, int) -GK_MKALLOC(gk_i32, int32_t) -GK_MKALLOC(gk_i64, int64_t) -GK_MKALLOC(gk_z, ssize_t) -GK_MKALLOC(gk_f, float) -GK_MKALLOC(gk_d, double) -GK_MKALLOC(gk_idx, gk_idx_t) +GK_MKALLOC(gk_c, char) +GK_MKALLOC(gk_i, int) +GK_MKALLOC(gk_i8, int8_t) +GK_MKALLOC(gk_i16, int16_t) +GK_MKALLOC(gk_i32, int32_t) +GK_MKALLOC(gk_i64, int64_t) +GK_MKALLOC(gk_ui8, uint8_t) +GK_MKALLOC(gk_ui16, uint16_t) +GK_MKALLOC(gk_ui32, uint32_t) +GK_MKALLOC(gk_ui64, uint64_t) +GK_MKALLOC(gk_z, ssize_t) +GK_MKALLOC(gk_zu, size_t) +GK_MKALLOC(gk_f, float) +GK_MKALLOC(gk_d, double) +GK_MKALLOC(gk_idx, gk_idx_t) GK_MKALLOC(gk_ckv, gk_ckv_t) GK_MKALLOC(gk_ikv, gk_ikv_t) +GK_MKALLOC(gk_i8kv, gk_i8kv_t) +GK_MKALLOC(gk_i16kv, gk_i16kv_t) GK_MKALLOC(gk_i32kv, gk_i32kv_t) GK_MKALLOC(gk_i64kv, gk_i64kv_t) GK_MKALLOC(gk_zkv, gk_zkv_t) +GK_MKALLOC(gk_zukv, gk_zukv_t) GK_MKALLOC(gk_fkv, gk_fkv_t) GK_MKALLOC(gk_dkv, gk_dkv_t) GK_MKALLOC(gk_skv, gk_skv_t) @@ -52,7 +62,7 @@ GK_MKALLOC(gk_idxkv, gk_idxkv_t) /*************************************************************************/ void gk_AllocMatrix(void ***r_matrix, size_t elmlen, size_t ndim1, size_t ndim2) { - gk_idx_t i, j; + size_t i, j; void **matrix; *r_matrix = NULL; @@ -78,7 +88,7 @@ void gk_AllocMatrix(void ***r_matrix, size_t elmlen, size_t ndim1, size_t ndim2) /*************************************************************************/ void gk_FreeMatrix(void ***r_matrix, size_t ndim1, size_t ndim2) { - gk_idx_t i; + size_t i; void **matrix; if ((matrix = *r_matrix) == NULL) @@ -157,11 +167,6 @@ void *gk_malloc(size_t nbytes, char *msg) /* add this memory allocation */ if (gkmcore != NULL) gk_gkmcoreAdd(gkmcore, GK_MOPT_HEAP, nbytes, ptr); - /* zero-out the allocated space */ -#ifndef NDEBUG - memset(ptr, 0, nbytes); -#endif - return ptr; } @@ -208,7 +213,8 @@ void gk_free(void **ptr1,...) free(*ptr1); /* remove this memory de-allocation */ - if (gkmcore != NULL) gk_gkmcoreDel(gkmcore, *ptr1); + if (gkmcore != NULL) + gk_gkmcoreDel(gkmcore, *ptr1); } *ptr1 = NULL; @@ -218,7 +224,8 @@ void gk_free(void **ptr1,...) free(*ptr); /* remove this memory de-allocation */ - if (gkmcore != NULL) gk_gkmcoreDel(gkmcore, *ptr); + if (gkmcore != NULL) + gk_gkmcoreDel(gkmcore, *ptr); } *ptr = NULL; } @@ -250,3 +257,26 @@ size_t gk_GetMaxMemoryUsed() else return gkmcore->max_hallocs; } + + +/*************************************************************************/ +/*! This function returns the VmSize and VmRSS of the calling process. */ +/*************************************************************************/ +void gk_GetVMInfo(size_t *vmsize, size_t *vmrss) +{ + FILE *fp; + char fname[1024]; + + sprintf(fname, "/proc/%d/statm", getpid()); + fp = gk_fopen(fname, "r", "proc/pid/statm"); + if (fscanf(fp, "%zu %zu", vmsize, vmrss) != 2) + errexit("Failed to read to values from %s\n", fname); + gk_fclose(fp); + + /* + *vmsize *= sysconf(_SC_PAGESIZE); + *vmrss *= sysconf(_SC_PAGESIZE); + */ + + return; +} diff --git a/3rdParty/metis/metis-5.1.0/GKlib/ms_inttypes.h b/3rdParty/metis/metis-5.1.1/GKlib/ms_inttypes.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/ms_inttypes.h rename to 3rdParty/metis/metis-5.1.1/GKlib/ms_inttypes.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/ms_stat.h b/3rdParty/metis/metis-5.1.1/GKlib/ms_stat.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/ms_stat.h rename to 3rdParty/metis/metis-5.1.1/GKlib/ms_stat.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/ms_stdint.h b/3rdParty/metis/metis-5.1.1/GKlib/ms_stdint.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/ms_stdint.h rename to 3rdParty/metis/metis-5.1.1/GKlib/ms_stdint.h diff --git a/3rdParty/metis/metis-5.1.0/GKlib/pqueue.c b/3rdParty/metis/metis-5.1.1/GKlib/pqueue.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/pqueue.c rename to 3rdParty/metis/metis-5.1.1/GKlib/pqueue.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/random.c b/3rdParty/metis/metis-5.1.1/GKlib/random.c similarity index 96% rename from 3rdParty/metis/metis-5.1.0/GKlib/random.c rename to 3rdParty/metis/metis-5.1.1/GKlib/random.c index d18e7188b16689acb38772f82f541a76404f0df5..36986146209e5b6160d3dcb9e6d77a3bcd7fd61b 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/random.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/random.c @@ -5,7 +5,7 @@ \date Started 5/17/2007 \author George -\version\verbatim $Id: random.c 11793 2012-04-04 21:03:02Z karypis $ \endverbatim +\version\verbatim $Id: random.c 18796 2015-06-02 11:39:45Z karypis $ \endverbatim */ #include <GKlib.h> @@ -16,10 +16,12 @@ /*************************************************************************/ GK_MKRANDOM(gk_c, size_t, char) GK_MKRANDOM(gk_i, size_t, int) +GK_MKRANDOM(gk_i32, size_t, int32_t) GK_MKRANDOM(gk_f, size_t, float) GK_MKRANDOM(gk_d, size_t, double) GK_MKRANDOM(gk_idx, size_t, gk_idx_t) GK_MKRANDOM(gk_z, size_t, ssize_t) +GK_MKRANDOM(gk_zu, size_t, size_t) diff --git a/3rdParty/metis/metis-5.1.0/GKlib/rw.c b/3rdParty/metis/metis-5.1.1/GKlib/rw.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/rw.c rename to 3rdParty/metis/metis-5.1.1/GKlib/rw.c diff --git a/3rdParty/metis/metis-5.1.1/GKlib/scripts/gexpand.pl b/3rdParty/metis/metis-5.1.1/GKlib/scripts/gexpand.pl new file mode 100755 index 0000000000000000000000000000000000000000..2b82134e7894842e821ed86d7dd3ac41786fd008 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/scripts/gexpand.pl @@ -0,0 +1,53 @@ +#!/usr/bin/perl -w + +die "Usage $0 <gfile> <ncopies>\n" unless @ARGV == 2; + +$filein = shift(@ARGV); +$ncopies = shift(@ARGV); + +open(FPIN, "<$filein") or die "Could not open $filein. $!\n"; + +$_ = <FPIN>; +chomp($_); +($nvtxs, $nedges) = split(' ', $_); + +#print "nvtxs: $nvtxs, nedges: $nedges\n"; + +$u = 1; +while (<FPIN>) { + chomp($_); + @edges = split(' ', $_); + + # put the within layer edges + foreach $v (@edges) { + next if $v < $u; + for ($i=0; $i<$ncopies; $i++) { + printf("%d %d\n", $i*$nvtxs+$u-1, $i*$nvtxs+$v-1); + printf("%d %d\n", $i*$nvtxs+$v-1, $i*$nvtxs+$u-1); + } + } + + # put the vertex across layer edges + for ($i=0; $i<$ncopies-1; $i++) { + printf("%d %d\n", $i*$nvtxs+$u-1, ($i+1)*$nvtxs+$u-1); + printf("%d %d\n", ($i+1)*$nvtxs+$u-1, $i*$nvtxs+$u-1); + } + + # put the adjacent across layer edges + for ($i=0; $i<$ncopies-1; $i++) { + $j=0; + foreach $v (@edges) { + $j++; + next if (($j+$i)%2 == 0); + printf("%d %d\n", $i*$nvtxs+$u-1, ($i+1)*$nvtxs+$v-1); + printf("%d %d\n", ($i+1)*$nvtxs+$v-1, $i*$nvtxs+$u-1); + } + } + + goto DONE; + +DONE: + $u++; +} + +close(FPIN); diff --git a/3rdParty/metis/metis-5.1.0/GKlib/seq.c b/3rdParty/metis/metis-5.1.1/GKlib/seq.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/seq.c rename to 3rdParty/metis/metis-5.1.1/GKlib/seq.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/sort.c b/3rdParty/metis/metis-5.1.1/GKlib/sort.c similarity index 74% rename from 3rdParty/metis/metis-5.1.0/GKlib/sort.c rename to 3rdParty/metis/metis-5.1.1/GKlib/sort.c index bde30f5a59f3a090697d79de49fb03460c86a539..f0144aeaae9b4eb5ea873e828d937b9967a36c91 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/sort.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/sort.c @@ -10,7 +10,7 @@ these routines where defined. \date Started 4/4/07 \author George -\version\verbatim $Id: sort.c 10796 2011-09-23 21:33:09Z karypis $ \endverbatim +\version\verbatim $Id: sort.c 21050 2017-05-25 03:53:58Z karypis $ \endverbatim */ #include <GKlib.h> @@ -61,6 +61,94 @@ void gk_isortd(size_t n, int *base) } +/*************************************************************************/ +/*! Sorts an array of integers in increasing order */ +/*************************************************************************/ +void gk_i32sorti(size_t n, int32_t *base) +{ +#define int_lt(a, b) ((*a) < (*b)) + GK_MKQSORT(int32_t, base, n, int_lt); +#undef int_lt +} + + +/*************************************************************************/ +/*! Sorts an array of integers in decreasing order */ +/*************************************************************************/ +void gk_i32sortd(size_t n, int32_t *base) +{ +#define int_gt(a, b) ((*a) > (*b)) + GK_MKQSORT(int32_t, base, n, int_gt); +#undef int_gt +} + + +/*************************************************************************/ +/*! Sorts an array of integers in increasing order */ +/*************************************************************************/ +void gk_i64sorti(size_t n, int64_t *base) +{ +#define int_lt(a, b) ((*a) < (*b)) + GK_MKQSORT(int64_t, base, n, int_lt); +#undef int_lt +} + + +/*************************************************************************/ +/*! Sorts an array of integers in increasing order */ +/*************************************************************************/ +void gk_ui32sorti(size_t n, uint32_t *base) +{ +#define int_lt(a, b) ((*a) < (*b)) + GK_MKQSORT(uint32_t, base, n, int_lt); +#undef int_lt +} + + +/*************************************************************************/ +/*! Sorts an array of integers in decreasing order */ +/*************************************************************************/ +void gk_ui32sortd(size_t n, uint32_t *base) +{ +#define int_gt(a, b) ((*a) > (*b)) + GK_MKQSORT(uint32_t, base, n, int_gt); +#undef int_gt +} + + +/*************************************************************************/ +/*! Sorts an array of integers in increasing order */ +/*************************************************************************/ +void gk_ui64sorti(size_t n, uint64_t *base) +{ +#define int_lt(a, b) ((*a) < (*b)) + GK_MKQSORT(uint64_t, base, n, int_lt); +#undef int_lt +} + + +/*************************************************************************/ +/*! Sorts an array of integers in decreasing order */ +/*************************************************************************/ +void gk_ui64sortd(size_t n, uint64_t *base) +{ +#define int_gt(a, b) ((*a) > (*b)) + GK_MKQSORT(uint64_t, base, n, int_gt); +#undef int_gt +} + + +/*************************************************************************/ +/*! Sorts an array of integers in decreasing order */ +/*************************************************************************/ +void gk_i64sortd(size_t n, int64_t *base) +{ +#define int_gt(a, b) ((*a) > (*b)) + GK_MKQSORT(int64_t, base, n, int_gt); +#undef int_gt +} + + /*************************************************************************/ /*! Sorts an array of floats in increasing order */ /*************************************************************************/ @@ -239,6 +327,28 @@ void gk_zkvsortd(size_t n, gk_zkv_t *base) } +/*************************************************************************/ +/*! Sorts an array of gk_zukv_t in increasing order */ +/*************************************************************************/ +void gk_zukvsorti(size_t n, gk_zukv_t *base) +{ +#define zukey_lt(a, b) ((a)->key < (b)->key) + GK_MKQSORT(gk_zukv_t, base, n, zukey_lt); +#undef zukey_lt +} + + +/*************************************************************************/ +/*! Sorts an array of gk_zukv_t in decreasing order */ +/*************************************************************************/ +void gk_zukvsortd(size_t n, gk_zukv_t *base) +{ +#define zukey_gt(a, b) ((a)->key > (b)->key) + GK_MKQSORT(gk_zukv_t, base, n, zukey_gt); +#undef zukey_gt +} + + /*************************************************************************/ /*! Sorts an array of gk_fkv_t in increasing order */ /*************************************************************************/ diff --git a/3rdParty/metis/metis-5.1.0/GKlib/string.c b/3rdParty/metis/metis-5.1.1/GKlib/string.c similarity index 98% rename from 3rdParty/metis/metis-5.1.0/GKlib/string.c rename to 3rdParty/metis/metis-5.1.1/GKlib/string.c index 5d28452ba8f75de1fd416fdee4c731d86ccf3769..562db22ef1edcadebfcc31d554531377af21f698 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/string.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/string.c @@ -9,7 +9,7 @@ of standard functions (but with enhanced functionality). \date Started 11/1/99 \author George -\version $Id: string.c 10711 2011-08-31 22:23:04Z karypis $ +\version $Id: string.c 14330 2013-05-18 12:15:15Z karypis $ */ /************************************************************************/ @@ -36,8 +36,7 @@ It tries to provide a functionality similar to Perl's \b tr// function. /************************************************************************/ char *gk_strchr_replace(char *str, char *fromlist, char *tolist) { - gk_idx_t i, j, k; - size_t len, fromlen, tolen; + ssize_t i, j, k, len, fromlen, tolen; len = strlen(str); fromlen = strlen(fromlist); @@ -94,9 +93,8 @@ based substitution function. int gk_strstr_replace(char *str, char *pattern, char *replacement, char *options, char **new_str) { - gk_idx_t i; + ssize_t i, len, rlen, nlen, offset, noffset; int j, rc, flags, global, nmatches; - size_t len, rlen, nlen, offset, noffset; regex_t re; regmatch_t matches[10]; @@ -253,8 +251,7 @@ This is a distructive operation as it modifies the string. /*************************************************************************/ char *gk_strtprune(char *str, char *rmlist) { - gk_idx_t i, j; - size_t len; + ssize_t i, j, len; len = strlen(rmlist); @@ -290,8 +287,7 @@ This is a distructive operation as it modifies the string. /*************************************************************************/ char *gk_strhprune(char *str, char *rmlist) { - gk_idx_t i, j; - size_t len; + ssize_t i, j, len; len = strlen(rmlist); diff --git a/3rdParty/metis/metis-5.1.1/GKlib/test/CMakeLists.txt b/3rdParty/metis/metis-5.1.1/GKlib/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..aab6308488f93203a3b4b4582b0d05162acd7e33 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/CMakeLists.txt @@ -0,0 +1,20 @@ +# Where the header files reside +#include_directories(../) + +# Build program. +add_executable(strings strings.c) +add_executable(gksort gksort.c) +add_executable(fis fis.c) +add_executable(gkrw rw.c) +add_executable(gkgraph gkgraph.c) +add_executable(csrcnv csrcnv.c) +add_executable(grKx grKx.c) +add_executable(m2mnbrs m2mnbrs.c) +add_executable(cmpnbrs cmpnbrs.c) +add_executable(splatt2svd splatt2svd.c) +foreach(prog strings gksort fis gkrw gkgraph csrcnv grKx m2mnbrs cmpnbrs splatt2svd) + target_link_libraries(${prog} GKlib) +endforeach(prog) + +# Install +install(TARGETS fis csrcnv m2mnbrs gkrw cmpnbrs gkgraph RUNTIME DESTINATION bin) diff --git a/3rdParty/metis/metis-5.1.1/GKlib/test/cmpnbrs.c b/3rdParty/metis/metis-5.1.1/GKlib/test/cmpnbrs.c new file mode 100644 index 0000000000000000000000000000000000000000..6e3ace820f38b40607c7add48123c091c1ffb111 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/cmpnbrs.c @@ -0,0 +1,301 @@ +/*! +\file +\brief It takes as input two CSR matrices A and B and computes how + similar AA' and A'A are to BB' and B'B, respectively in terms + of the cosine similarity of the corresponding rows. + +\date 11/09/2015 +\author George +\version \verbatim $Id: m2mnbrs.c 17699 2014-09-27 18:05:31Z karypis $ \endverbatim +*/ + +#include <GKlib.h> + +/*************************************************************************/ +/*! Data structures for the code */ +/*************************************************************************/ +typedef struct { + int simtype; /*!< The similarity type to use */ + int verbosity; /*!< The reporting verbosity level */ + + char *afile; /*!< The file storing the query documents */ + char *bfile; /*!< The file storing the collection documents */ + + /* timers */ + double timer_global; +} params_t; + + +/*************************************************************************/ +/*! Constants */ +/*************************************************************************/ +/* Versions */ +#define VER_MAJOR 0 +#define VER_MINOR 1 +#define VER_SUBMINOR 0 + +/* Command-line option codes */ +#define CMD_SIMTYPE 10 +#define CMD_VERBOSITY 70 +#define CMD_HELP 100 + +/* The text labels for the different simtypes */ +static char simtypenames[][10] = {"", "dotp", "cos", "jac", ""}; + + +/*************************************************************************/ +/*! Local variables */ +/*************************************************************************/ +static struct gk_option long_options[] = { + {"simtype", 1, 0, CMD_SIMTYPE}, + {"verbosity", 1, 0, CMD_VERBOSITY}, + + {"help", 0, 0, CMD_HELP}, + {0, 0, 0, 0} +}; + +static gk_StringMap_t simtype_options[] = { + {"dotp", GK_CSR_DOTP}, + {"cos", GK_CSR_COS}, + {"jac", GK_CSR_JAC}, + {NULL, 0} +}; + + +/*------------------------------------------------------------------- + * Mini help + *-------------------------------------------------------------------*/ +static char helpstr[][100] = +{ +" ", +"Usage: cmpnbrs [options] afile bfile", +" ", +" Options", +" -simtype=string", +" Specifies the type of similarity to use. Possible values are:", +" dotp - Dot-product similarity [default]", +" cos - Cosine similarity", +" jac - Jacquard similarity", +" ", +" -verbosity=int", +" Specifies the level of debugging information to be displayed.", +" Default value is 0.", +" ", +" -help", +" Prints this message.", +"" +}; + + + +/*************************************************************************/ +/*! Function prototypes */ +/*************************************************************************/ +params_t *parse_cmdline(int argc, char *argv[]); +double ComputeNeighborhoodSimilarity(params_t *params, gk_csr_t *amat, gk_csr_t *bmat); + + +/*************************************************************************/ +/*! This is the entry point of the command-line argument parser */ +/*************************************************************************/ +params_t *parse_cmdline(int argc, char *argv[]) +{ + int i; + int c, option_index; + params_t *params; + + params = (params_t *)gk_malloc(sizeof(params_t), "parse_cmdline: params"); + + /* initialize the params data structure */ + params->simtype = GK_CSR_DOTP; + params->verbosity = -1; + params->afile = NULL; + params->bfile = NULL; + + + /* Parse the command line arguments */ + while ((c = gk_getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { + switch (c) { + case CMD_SIMTYPE: + if (gk_optarg) { + if ((params->simtype = gk_GetStringID(simtype_options, gk_optarg)) == -1) + errexit("Invalid simtype of %s.\n", gk_optarg); + } + break; + + case CMD_VERBOSITY: + if (gk_optarg) params->verbosity = atoi(gk_optarg); + break; + + case CMD_HELP: + for (i=0; strlen(helpstr[i]) > 0; i++) + printf("%s\n", helpstr[i]); + exit(EXIT_SUCCESS); + break; + + case '?': + default: + printf("Illegal command-line option(s)\nUse %s -help for a summary of the options.\n", argv[0]); + exit(EXIT_FAILURE); + } + } + + /* Get the input/output file info */ + if (argc-gk_optind != 2) { + printf("Missing input file info.\n Use %s -help for a summary of the options.\n", argv[0]); + exit(EXIT_FAILURE); + } + + params->afile = gk_strdup(argv[gk_optind++]); + params->bfile = gk_strdup(argv[gk_optind++]); + + if (!gk_fexists(params->afile)) + errexit("input file %s does not exist.\n", params->afile); + if (!gk_fexists(params->bfile)) + errexit("input file %s does not exist.\n", params->bfile); + + return params; +} + + +/*************************************************************************/ +/*! This is the entry point of the program */ +/**************************************************************************/ +int main(int argc, char *argv[]) +{ + params_t *params; + gk_csr_t *amat, *bmat, *amatt, *bmatt; + int rc = EXIT_SUCCESS; + + params = parse_cmdline(argc, argv); + + amat = gk_csr_Read(params->afile, GK_CSR_FMT_CSR, 1, 0); + bmat = gk_csr_Read(params->bfile, GK_CSR_FMT_CSR, 1, 0); + + /* make the matrices of similar dimensions (if neccessary) */ + GKASSERT(amat->nrows == bmat->nrows); + amat->ncols = gk_max(amat->ncols, bmat->ncols); + bmat->ncols = amat->ncols; + + /* create the transpose matrices */ + amatt = gk_csr_Transpose(amat); + bmatt = gk_csr_Transpose(bmat); + + printf("********************************************************************************\n"); + printf("cmpnbrs (%d.%d.%d) Copyright 2015, GK.\n", VER_MAJOR, VER_MINOR, VER_SUBMINOR); + printf(" simtype=%s\n", + simtypenames[params->simtype]); + printf(" afile=%s, nrows=%d, ncols=%d, nnz=%zd\n", + params->afile, amat->nrows, amat->ncols, amat->rowptr[amat->nrows]); + printf(" bfile=%s, nrows=%d, ncols=%d, nnz=%zd\n", + params->bfile, bmat->nrows, bmat->ncols, bmat->rowptr[bmat->nrows]); + + gk_clearwctimer(params->timer_global); + gk_startwctimer(params->timer_global); + + printf("SIM(AA', BB'): %.5lf\t", ComputeNeighborhoodSimilarity(params, amat, bmat)); + printf("SIM(A'A, B'B): %.5lf\n", ComputeNeighborhoodSimilarity(params, amatt, bmatt)); + + gk_stopwctimer(params->timer_global); + + printf(" wclock: %.2lfs\n", gk_getwctimer(params->timer_global)); + printf("********************************************************************************\n"); + + gk_csr_Free(&amat); + gk_csr_Free(&bmat); + gk_csr_Free(&amatt); + gk_csr_Free(&bmatt); + + exit(rc); +} + + +/*************************************************************************/ +/*! Compares the neighbors of AA' vs BB' */ +/**************************************************************************/ +double ComputeNeighborhoodSimilarity(params_t *params, gk_csr_t *amat, + gk_csr_t *bmat) +{ + int iR, iH, nahits, nbhits, ncmps; + int32_t *marker; + gk_fkv_t *ahits, *bhits, *cand; + double tabsim, abdot, anorm2, bnorm2, *avec, *bvec; + + /* if cosine, make rows unit length */ + if (params->simtype == GK_CSR_COS) { + gk_csr_Normalize(amat, GK_CSR_ROW, 2); + gk_csr_Normalize(bmat, GK_CSR_ROW, 2); + } + + /* create the inverted index */ + gk_csr_CreateIndex(amat, GK_CSR_COL); + gk_csr_CreateIndex(bmat, GK_CSR_COL); + + /* compute the row squared norms */ + gk_csr_ComputeSquaredNorms(amat, GK_CSR_ROW); + gk_csr_ComputeSquaredNorms(bmat, GK_CSR_ROW); + + + /* allocate memory for the necessary working arrays */ + ahits = gk_fkvmalloc(amat->nrows, "ComputeNeighborhoodSimilarity: ahits"); + bhits = gk_fkvmalloc(bmat->nrows, "ComputeNeighborhoodSimilarity: bhits"); + marker = gk_i32smalloc(amat->nrows, -1, "ComputeNeighborhoodSimilarity: marker"); + cand = gk_fkvmalloc(amat->nrows, "ComputeNeighborhoodSimilarity: cand"); + avec = gk_dsmalloc(amat->nrows, 0.0, "ComputeNeighborhoodSimilarity: avec"); + bvec = gk_dsmalloc(bmat->nrows, 0.0, "ComputeNeighborhoodSimilarity: bvec"); + + + /* find the best neighbors for each row in the two matrices and compute + the cosine similarity between them. */ + tabsim = 0.0; + ncmps = 0; + for (iR=0; iR<amat->nrows; iR++) { + if (params->verbosity > 1) + printf("Working on row %7d\n", iR); + + if (amat->rowptr[iR+1]-amat->rowptr[iR] == 0 || + bmat->rowptr[iR+1]-bmat->rowptr[iR] == 0) + continue; + + nahits = gk_csr_GetSimilarRows(amat, + amat->rowptr[iR+1]-amat->rowptr[iR], + amat->rowind+amat->rowptr[iR], + amat->rowval+amat->rowptr[iR], + params->simtype, amat->nrows, 0.0, + ahits, marker, cand); + + nbhits = gk_csr_GetSimilarRows(bmat, + bmat->rowptr[iR+1]-bmat->rowptr[iR], + bmat->rowind+bmat->rowptr[iR], + bmat->rowval+bmat->rowptr[iR], + params->simtype, bmat->nrows, 0.0, + bhits, marker, cand); + + if (params->verbosity > 0) + printf("Row %7d %7d %7d %8zd %8zd\n", iR, nahits, nbhits, + amat->rowptr[iR+1]-amat->rowptr[iR], bmat->rowptr[iR+1]-bmat->rowptr[iR]); + + for (iH=0; iH<nahits; iH++) + avec[ahits[iH].val] = ahits[iH].key; + for (iH=0; iH<nbhits; iH++) + bvec[bhits[iH].val] = bhits[iH].key; + + for (abdot=anorm2=bnorm2=0.0, iH=0; iH<amat->nrows; iH++) { + abdot += avec[iH]*bvec[iH]; + anorm2 += avec[iH]*avec[iH]; + bnorm2 += bvec[iH]*bvec[iH]; + } + tabsim += (abdot > 0 ? abdot/sqrt(anorm2*bnorm2) : 0.0); + ncmps++; + + for (iH=0; iH<nahits; iH++) + avec[ahits[iH].val] = 0.0; + for (iH=0; iH<nbhits; iH++) + bvec[bhits[iH].val] = 0.0; + } + + gk_free((void **)&ahits, &bhits, &marker, &cand, &avec, &bvec, LTERM); + + return tabsim/ncmps; +} + diff --git a/3rdParty/metis/metis-5.1.1/GKlib/test/csrcnv.c b/3rdParty/metis/metis-5.1.1/GKlib/test/csrcnv.c new file mode 100644 index 0000000000000000000000000000000000000000..aef808ef2a7deeaf9c85f62776c741ad601f16fd --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/csrcnv.c @@ -0,0 +1,397 @@ +/*! +\file +\brief A simple program to convert between different matrix formats that are supported + by the gk_csr_Read/gk_csr_Write functions. + +\date 5/30/2013 +\author George +\version \verbatim $Id: csrcnv.c 15314 2013-10-05 16:50:50Z karypis $ \endverbatim +*/ + +#include <GKlib.h> + +/*************************************************************************/ +/*! Data structures for the code */ +/*************************************************************************/ +typedef struct { + int inf, outf; /* input/output format */ + int numbering; /* input numbering (output when applicable) */ + int readvals; /* input values (output when applicable) */ + int writevals; /* output values */ + int rshuf, cshuf; /* random shuffle of rows/columns */ + int symmetric; /* a symmetric shuffle */ + int mincolfreq; /* column prunning */ + int maxcolfreq; /* column prunning */ + int minrowfreq; /* row prunning */ + int maxrowfreq; /* row prunning */ + float rownrmfltr; /* row-lowfilter threshold */ + int compactcols; /* if to renumber columns to eliminate empty ones */ + int transpose; /* transpose the output matrix */ + char *srenumber; /* the iperm file for the symmetric renumbering */ + char *infile; /* input file */ + char *outfile; /* output file */ +} params_t; + + +/*************************************************************************/ +/*! Constants */ +/*************************************************************************/ +#define CMD_NUMONE 1 +#define CMD_NOREADVALS 2 +#define CMD_NOWRITEVALS 3 +#define CMD_RSHUF 4 +#define CMD_CSHUF 5 +#define CMD_SYMMETRIC 6 +#define CMD_MINCOLFREQ 7 +#define CMD_MAXCOLFREQ 8 +#define CMD_MINROWFREQ 9 +#define CMD_MAXROWFREQ 10 +#define CMD_ROWNRMFLTR 11 +#define CMD_COMPACTCOLS 12 +#define CMD_TRANSPOSE 13 +#define CMD_SRENUMBER 14 +#define CMD_HELP 100 + + +/*************************************************************************/ +/*! Local variables */ +/*************************************************************************/ +static struct gk_option long_options[] = { + {"numone", 0, 0, CMD_NUMONE}, + {"noreadvals", 0, 0, CMD_NOREADVALS}, + {"nowritevals", 0, 0, CMD_NOWRITEVALS}, + {"rshuf", 0, 0, CMD_RSHUF}, + {"cshuf", 0, 0, CMD_CSHUF}, + {"symmetric", 0, 0, CMD_SYMMETRIC}, + {"mincolfreq", 1, 0, CMD_MINCOLFREQ}, + {"maxcolfreq", 1, 0, CMD_MAXCOLFREQ}, + {"minrowfreq", 1, 0, CMD_MINROWFREQ}, + {"maxrowfreq", 1, 0, CMD_MAXROWFREQ}, + {"rownrmfltr", 1, 0, CMD_ROWNRMFLTR}, + {"compactcols", 0, 0, CMD_COMPACTCOLS}, + {"transpose", 0, 0, CMD_TRANSPOSE}, + {"srenumber", 1, 0, CMD_SRENUMBER}, + {"help", 0, 0, CMD_HELP}, + {0, 0, 0, 0} +}; + + +/*-------------------------------------------------------------------*/ +/* Mini help */ +/*-------------------------------------------------------------------*/ +static char helpstr[][100] = { +" ", +"Usage: csrconv [options] <infile> <inf> <outfile> <outf>", +" ", +" Required parameters", +" infile, outfile", +" The name of the input/output CSR file.", +" ", +" inf/outf", +" The format of the input/output file.", +" Supported values are:", +" 1 GK_CSR_FMT_CLUTO", +" 2 GK_CSR_FMT_CSR", +" 3 GK_CSR_FMT_METIS", +" 4 GK_CSR_FMT_BINROW", +" 6 GK_CSR_FMT_IJV", +" 7 GK_CSR_FMT_BIJV", +" ", +" Optional parameters", +" -numone", +" Specifies that the numbering of the input file starts from 1. ", +" It only applies to CSR/IJV formats.", +" ", +" -nowritevals", +" Specifies that no values will be output.", +" ", +" -noreadvals", +" Specifies that the values will not be read when applicable.", +" ", +" -rshuf", +" Specifies that the rows will be randmly shuffled prior to output.", +" ", +" -cshuf", +" Specifies that the columns will be randmly shuffled prior to output.", +" ", +" -symmetric", +" Specifies that the row+column shuffling will be symmetric.", +" ", +" -mincolfreq=int", +" Used to prune infrequent columns.", +" ", +" -maxcolfreq=int", +" Used to prune frequent columns.", +" ", +" -minrowfreq=int", +" Used to prune infrequent rows.", +" ", +" -maxrowfreq=int", +" Used to prune frequent.", +" ", +" -rownrmfltr=float", +" The parameter to use for the row-wise low filter.", +" ", +" -compactcols", +" Specifies if empty columns will be removed and the columns renumbered.", +" ", +" -transpose", +" Specifies that the transposed matrix will be written.", +" ", +" -srenumber=iperm-file", +" Performs a symmetric renumbering based on the provided iperm file.", +" ", +" -help", +" Prints this message.", +"" +}; + +static char shorthelpstr[][100] = { +" ", +" Usage: csrconv [options] <infile> <inf> <outfile> <outf>", +" use 'csrconv -help' for a summary of the options.", +"" +}; + + +/*************************************************************************/ +/*! This is the entry point of the command-line argument parser */ +/*************************************************************************/ +params_t *parse_cmdline(int argc, char *argv[]) +{ + int i; + int c, option_index; + params_t *params; + + params = (params_t *)gk_malloc(sizeof(params_t), "parse_cmdline: params"); + + /* initialize the params data structure */ + params->numbering = 0; + params->readvals = 1; + params->writevals = 1; + params->rshuf = 0; + params->cshuf = 0; + params->symmetric = 0; + params->transpose = 0; + params->srenumber = NULL; + + params->mincolfreq = -1; + params->minrowfreq = -1; + params->maxcolfreq = -1; + params->maxrowfreq = -1; + params->rownrmfltr = -1; + params->compactcols = 0; + + params->inf = -1; + params->outf = -1; + params->infile = NULL; + params->outfile = NULL; + + + /* Parse the command line arguments */ + while ((c = gk_getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { + switch (c) { + case CMD_NUMONE: + params->numbering = 1; + break; + case CMD_NOREADVALS: + params->readvals = 0; + break; + case CMD_NOWRITEVALS: + params->writevals = 0; + break; + case CMD_RSHUF: + params->rshuf = 1; + break; + case CMD_CSHUF: + params->cshuf = 1; + break; + case CMD_SYMMETRIC: + params->symmetric = 1; + break; + case CMD_TRANSPOSE: + params->transpose = 1; + break; + + + case CMD_MINCOLFREQ: + if (gk_optarg) params->mincolfreq = atoi(gk_optarg); + break; + case CMD_MINROWFREQ: + if (gk_optarg) params->minrowfreq = atoi(gk_optarg); + break; + case CMD_MAXCOLFREQ: + if (gk_optarg) params->maxcolfreq = atoi(gk_optarg); + break; + case CMD_MAXROWFREQ: + if (gk_optarg) params->maxrowfreq = atoi(gk_optarg); + break; + case CMD_ROWNRMFLTR: + if (gk_optarg) params->rownrmfltr = atof(gk_optarg); + break; + case CMD_COMPACTCOLS: + params->compactcols = 1; + break; + + case CMD_SRENUMBER: + if (gk_optarg) { + params->srenumber = gk_strdup(gk_optarg); + if (!gk_fexists(params->srenumber)) + errexit("srenumber file %s does not exist.\n", params->srenumber); + } + break; + + case CMD_HELP: + for (i=0; strlen(helpstr[i]) > 0; i++) + printf("%s\n", helpstr[i]); + exit(0); + break; + case '?': + default: + printf("Illegal command-line option(s)\nUse %s -help for a summary of the options.\n", argv[0]); + exit(0); + } + } + + if (argc-gk_optind != 4) { + printf("Unrecognized parameters."); + for (i=0; strlen(shorthelpstr[i]) > 0; i++) + printf("%s\n", shorthelpstr[i]); + exit(0); + } + + params->infile = gk_strdup(argv[gk_optind++]); + params->inf = atoi(argv[gk_optind++]); + params->outfile = gk_strdup(argv[gk_optind++]); + params->outf = atoi(argv[gk_optind++]); + + if (!gk_fexists(params->infile)) + errexit("input file %s does not exist.\n", params->infile); + + return params; +} + + +/*************************************************************************/ +/*! the entry point */ +/**************************************************************************/ +int main(int argc, char *argv[]) +{ + int what; + params_t *params; + gk_csr_t *mat, *mat1, *smat; + + /* get command-line options */ + params = parse_cmdline(argc, argv); + + /* read the data */ + mat = gk_csr_Read(params->infile, params->inf, params->readvals, params->numbering); + + /* deal with weird transformations */ + if (params->mincolfreq != -1 || params->maxcolfreq != -1) { + params->mincolfreq = (params->mincolfreq == -1 ? 0 : params->mincolfreq); + params->maxcolfreq = (params->maxcolfreq == -1 ? mat->nrows : params->maxcolfreq); + + printf("Column prune: %d %d; nnz: %zd => ", + params->mincolfreq, params->maxcolfreq, mat->rowptr[mat->nrows]); + mat1 = gk_csr_Prune(mat, GK_CSR_COL, params->mincolfreq, params->maxcolfreq); + gk_csr_Free(&mat); + mat = mat1; + mat1 = NULL; + + printf("%zd\n", mat->rowptr[mat->nrows]); + } + + if (params->minrowfreq != -1 || params->maxrowfreq != -1) { + params->minrowfreq = (params->minrowfreq == -1 ? 0 : params->minrowfreq); + params->maxrowfreq = (params->maxrowfreq == -1 ? mat->ncols : params->maxrowfreq); + + printf("Row prune: %d %d; nnz: %zd => ", + params->minrowfreq, params->maxrowfreq, mat->rowptr[mat->nrows]); + mat1 = gk_csr_Prune(mat, GK_CSR_ROW, params->minrowfreq, params->maxrowfreq); + gk_csr_Free(&mat); + mat = mat1; + mat1 = NULL; + + printf("%zd\n", mat->rowptr[mat->nrows]); + } + + if (params->rownrmfltr >= 0.0) { + //gk_csr_Scale(mat, GK_CSR_LOG); + //gk_csr_Scale(mat, GK_CSR_IDF2); + + printf("Row low filter: %f; nnz: %zd => ", params->rownrmfltr, mat->rowptr[mat->nrows]); + mat1 = gk_csr_LowFilter(mat, GK_CSR_ROW, 2, params->rownrmfltr); + gk_csr_Normalize(mat1, GK_CSR_ROW, 2); + + gk_csr_Free(&mat); + mat = mat1; + mat1 = NULL; + + printf("%zd\n", mat->rowptr[mat->nrows]); + } + + if (params->compactcols) { + printf("Compacting columns: %d => ", mat->ncols); + gk_csr_CompactColumns(mat); + printf("%d\n", mat->ncols); + } + + + if (params->rshuf || params->cshuf) { + if (params->rshuf && params->cshuf) + what = GK_CSR_ROWCOL; + else if (params->rshuf) + what = GK_CSR_ROW; + else + what = GK_CSR_COL; + + smat = gk_csr_Shuffle(mat, what, params->symmetric); + gk_csr_Free(&mat); + mat = smat; + } + + + if (params->srenumber) { + int32_t i; + size_t nlines; + int32_t *iperm; + gk_csr_t *smat; + + iperm = gk_i32readfile(params->srenumber, &nlines); + if (nlines != mat->nrows && nlines != mat->ncols) + errexit("The nlines=%zud of srenumber file does not match nrows: %d, ncols: %d\n", nlines, mat->nrows, mat->ncols); + + if (gk_i32max(nlines, iperm, 1) >= nlines && gk_i32min(nlines, iperm, 1) <= 0) + errexit("The srenumber iperm seems to be wrong.\n"); + + if (gk_i32max(nlines, iperm, 1) == nlines) { /* need to renumber */ + for (i=0; i<nlines; i++) + iperm[i]--; + } + + smat = gk_csr_ReorderSymmetric(mat, iperm, NULL); + gk_csr_Free(&mat); + mat = smat; + + gk_free((void **)&iperm, LTERM); + } + + if (params->writevals && mat->rowval == NULL) + mat->rowval = gk_fsmalloc(mat->rowptr[mat->nrows], 1.0, "mat->rowval"); + + if (params->transpose) { + mat1 = gk_csr_Transpose(mat); + gk_csr_Free(&mat); + mat = mat1; + mat1 = NULL; + } + + + + gk_csr_Write(mat, params->outfile, params->outf, params->writevals, 0); + + gk_csr_Free(&mat); + +} + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/fis.c b/3rdParty/metis/metis-5.1.1/GKlib/test/fis.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/test/fis.c rename to 3rdParty/metis/metis-5.1.1/GKlib/test/fis.c diff --git a/3rdParty/metis/metis-5.1.1/GKlib/test/gkgraph.c b/3rdParty/metis/metis-5.1.1/GKlib/test/gkgraph.c new file mode 100644 index 0000000000000000000000000000000000000000..91314647ba1460826dcd5c31fbb07802a374f45d --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/gkgraph.c @@ -0,0 +1,845 @@ +/*! +\file +\brief A simple program to try out some graph routines + +\date 6/12/2008 +\author George +\version \verbatim $Id: gkgraph.c 17700 2014-09-27 18:10:02Z karypis $ \endverbatim +*/ + +#include <GKlib.h> + + +/*************************************************************************/ +/*! Data structures for the code */ +/*************************************************************************/ +typedef struct { + int lnbits; + int cnbits; + int type; + int niter; + float eps; + float lamda; + int nosort; + int write; + + char *infile; + char *outfile; +} params_t; + +/*************************************************************************/ +/*! Constants */ +/*************************************************************************/ +#define CMD_NITER 1 +#define CMD_EPS 2 +#define CMD_LAMDA 3 +#define CMD_TYPE 4 +#define CMD_NOSORT 5 +#define CMD_WRITE 6 +#define CMD_LNBITS 7 +#define CMD_CNBITS 8 +#define CMD_HELP 10 + +#define CLINE32 16 +#define CLINE64 8 +#define MAXRCLOCKSPAN (1<<20) + +/*************************************************************************/ +/*! Local variables */ +/*************************************************************************/ +static struct gk_option long_options[] = { + {"lnbits", 1, 0, CMD_LNBITS}, + {"cnbits", 1, 0, CMD_CNBITS}, + {"type", 1, 0, CMD_TYPE}, + {"niter", 1, 0, CMD_NITER}, + {"lamda", 1, 0, CMD_LAMDA}, + {"eps", 1, 0, CMD_EPS}, + {"nosort", 0, 0, CMD_NOSORT}, + {"write", 0, 0, CMD_WRITE}, + {"help", 0, 0, CMD_HELP}, + {0, 0, 0, 0} +}; + + +/*-------------------------------------------------------------------*/ +/* Mini help */ +/*-------------------------------------------------------------------*/ +static char helpstr[][100] = { +" ", +"Usage: gkgraph [options] <graph-file> [<out-file>]", +" ", +" Required parameters", +" graph-file", +" The name of the file storing the graph. The file is in ", +" Metis' graph format.", +" ", +" Optional parameters", +" -niter=int", +" Specifies the maximum number of iterations. [default: 100]", +" ", +" -lnbits=int", +" Specifies the number of address bits indexing the cacheline. [default: 6]", +" ", +" -cnbits=int", +" Specifies the number of address bits indexing the cache. [default: 13]", +" ", +" -lamda=float", +" Specifies the follow-the-adjacent-links probability. [default: 0.80]", +" ", +" -eps=float", +" Specifies the error tollerance. [default: 1e-10]", +" ", +" -nosort", +" Does not sort the adjacency lists.", +" ", +" -write", +" Output the reordered graphs.", +" ", +" -help", +" Prints this message.", +"" +}; + +static char shorthelpstr[][100] = { +" ", +" Usage: gkgraph [options] <graph-file> [<out-file>]", +" use 'gkgraph -help' for a summary of the options.", +"" +}; + + + +/*************************************************************************/ +/*! Function prototypes */ +/*************************************************************************/ +void test_spmv(params_t *params); +void test_tc(params_t *params); +void sort_adjacencies(params_t *params, gk_graph_t *graph); +double compute_spmvstats(params_t *params, gk_graph_t *graph); +double compute_tcstats(params_t *params, gk_graph_t *graph, int32_t *iperm); +int32_t *reorder_degrees(params_t *params, gk_graph_t *graph); +int32_t *reorder_freqlpn(params_t *params, gk_graph_t *graph); +int32_t *reorder_freqlpn_db(params_t *params, gk_graph_t *graph); +int32_t *reorder_minlpn(params_t *params, gk_graph_t *graph); +int32_t *reorder_minlpn_db(params_t *params, gk_graph_t *graph); +void print_init_info(params_t *params, gk_graph_t *graph); +void print_final_info(params_t *params); +params_t *parse_cmdline(int argc, char *argv[]); + + +/*************************************************************************/ +/*! the entry point */ +/**************************************************************************/ +int main(int argc, char *argv[]) +{ + params_t *params; + + /* get command-line options */ + params = parse_cmdline(argc, argv); + + test_tc(params); +} + + +/*************************************************************************/ +/*! various spmv-related tests */ +/**************************************************************************/ +void test_spmv(params_t *params) +{ + ssize_t i, j, v; + gk_graph_t *graph, *pgraph; + int32_t *perm; + + /* read the data */ + graph = gk_graph_Read(params->infile, GK_GRAPH_FMT_METIS, -1, -1, 0, 0, 0); + + /* display some basic stats */ + print_init_info(params, graph); + + sort_adjacencies(params, graph); + if (params->write) gk_graph_Write(graph, "original.ijv", GK_GRAPH_FMT_IJV, 1); + printf("Input SPMV HitRate: %.4lf\n", compute_spmvstats(params, graph)); + + + v = RandomInRange(graph->nvtxs); + gk_graph_ComputeBFSOrdering(graph, v, &perm, NULL); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "bfs.ijv", GK_GRAPH_FMT_IJV, 1); + printf("BFS SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); + + + perm = reorder_degrees(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "degrees.ijv", GK_GRAPH_FMT_IJV, 1); + printf("Degrees SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); + + + perm = reorder_freqlpn(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "freqlpn.ijv", GK_GRAPH_FMT_IJV, 1); + printf("FreqLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); + + perm = reorder_freqlpn_db(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "freqlpn-db.ijv", GK_GRAPH_FMT_IJV, 1); + printf("DBFreqLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); + + perm = reorder_minlpn(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "minlpn.ijv", GK_GRAPH_FMT_IJV, 1); + printf("MinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); + + perm = reorder_minlpn_db(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "minlpn-db.ijv", GK_GRAPH_FMT_IJV, 1); + printf("DBMinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); + + gk_graph_Free(&graph); + + print_final_info(params); + + return; +} + + +/*************************************************************************/ +/*! various tc-related tests */ +/**************************************************************************/ +void test_tc(params_t *params) +{ + ssize_t i, j, v; + gk_graph_t *graph, *pgraph; + int32_t *perm, *iperm; + + /* read the data */ + graph = gk_graph_Read(params->infile, GK_GRAPH_FMT_METIS, -1, -1, 0, 0, 0); + + /* display some basic stats */ + print_init_info(params, graph); + + perm = reorder_degrees(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + gk_free((void **)&perm, LTERM); + sort_adjacencies(params, pgraph); + iperm = gk_i32incset(graph->nvtxs, 0, gk_i32malloc(graph->nvtxs, "iperm")); + printf("Degrees TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm)); + + + sort_adjacencies(params, pgraph); + v = RandomInRange(pgraph->nvtxs); + gk_graph_ComputeBFSOrdering(pgraph, v, &perm, NULL); + for (i=0; i<graph->nvtxs; i++) iperm[perm[i]] = i; + gk_free((void **)&perm, LTERM); + printf("BFS TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm)); + + + sort_adjacencies(params, pgraph); + perm = reorder_freqlpn(params, pgraph); + for (i=0; i<graph->nvtxs; i++) iperm[perm[i]] = i; + gk_free((void **)&perm, LTERM); + printf("FreqLabelPropN TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm)); + + sort_adjacencies(params, pgraph); + perm = reorder_freqlpn_db(params, pgraph); + for (i=0; i<graph->nvtxs; i++) iperm[perm[i]] = i; + gk_free((void **)&perm, LTERM); + printf("DBFreqLabelPropN TC HitRate: %.4lf\n", compute_tcstats(params, pgraph, iperm)); + + +#ifdef XXX + perm = reorder_minlpn(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "minlpn.ijv", GK_GRAPH_FMT_IJV, 1); + printf("MinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); + + perm = reorder_minlpn_db(params, graph); + pgraph = gk_graph_Reorder(graph, perm, NULL); + sort_adjacencies(params, pgraph); + if (params->write) gk_graph_Write(pgraph, "minlpn-db.ijv", GK_GRAPH_FMT_IJV, 1); + printf("DBMinLabelPropN SPMV HitRate: %.4lf\n", compute_spmvstats(params, pgraph)); + gk_graph_Free(&pgraph); + gk_free((void **)&perm, LTERM); +#endif + + gk_free((void **)&iperm, LTERM); + gk_graph_Free(&graph); + + print_final_info(params); + + return; +} + + +/*************************************************************************/ +/*! This function sorts the adjacency lists of the vertices in increasing + order. +*/ +/*************************************************************************/ +void sort_adjacencies(params_t *params, gk_graph_t *graph) +{ + uint64_t i, nvtxs; + ssize_t *xadj; + int32_t *adjncy; + + if (params->nosort) + return; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + for (i=0; i<nvtxs; i++) + gk_i32sorti(xadj[i+1]-xadj[i], adjncy+xadj[i]); + + return; +} + + +/*************************************************************************/ +/*! This function analyzes the cache locality of an SPMV operation using + GKlib's cache simulator and returns the cache's hit rate. + */ +/*************************************************************************/ +double compute_spmvstats(params_t *params, gk_graph_t *graph) +{ + uint64_t i, nvtxs; + ssize_t *xadj; + int32_t *adjncy, *vec; + + gk_cache_t *cache = gk_cacheCreate(16, params->lnbits, params->cnbits); /* 8MB total; i7 spec */ + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + vec = gk_i32malloc(nvtxs, "vec"); + for (i=0; i<xadj[nvtxs]; i++) { + gk_cacheLoad(cache, (size_t)(&adjncy[i])); + gk_cacheLoad(cache, (size_t)(&vec[adjncy[i]])); + } + + gk_free((void **)&vec, LTERM); + + double hitrate = gk_cacheGetHitRate(cache); + gk_cacheDestroy(&cache); + + return hitrate; +} + + +/*************************************************************************/ +/*! The hash-map-based triangle-counting routine that uses the JIK + triangle enumeration scheme. + + This version implements the following: + - It does not store location information in L + - Reverts the order within U's adjancency lists to allow ++ traversal +*/ +/*************************************************************************/ +double compute_tcstats(params_t *params, gk_graph_t *graph, int32_t *iperm) +{ + int32_t vi, vj, vjj, vk, vl, nvtxs; + ssize_t ei, eiend, eistart, ej, ejend, ejstart; + int64_t ntriangles; + ssize_t *xadj, *uxadj; + int32_t *adjncy; + int32_t l, hmsize, *hmap; + + gk_cache_t *cache = gk_cacheCreate(16, params->lnbits, params->cnbits); + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + /* determine the starting location of the upper trianglular part */ + uxadj = gk_zmalloc(nvtxs, "uxadj"); + for (vi=0; vi<nvtxs; vi++) { + for (ei=xadj[vi], eiend=xadj[vi+1]; ei<eiend && adjncy[ei]<vi; ei++); + uxadj[vi] = ei; + /* flip the order of Adj(vi)'s upper triangular adjacency list */ + for (ej=xadj[vi+1]-1; ei<ej; ei++, ej--) { + vj = adjncy[ei]; + adjncy[ei] = adjncy[ej]; + adjncy[ej] = vj; + } + } + + /* determine the size of the hash-map and convert it into a format + that is compatible with a bitwise AND operation */ + for (hmsize=0, vi=0; vi<nvtxs; vi++) + hmsize = gk_max(hmsize, (int32_t)(xadj[vi+1]-uxadj[vi])); + for (l=1; hmsize>(1<<l); l++); + hmsize = (1<<(l+4))-1; + hmap = gk_i32smalloc(hmsize+1, 0, "hmap"); + + for (ntriangles=0, vjj=0; vjj<nvtxs; vjj++) { + vj = iperm[vjj]; + + gk_cacheLoad(cache, (size_t)(&xadj[vj])); + gk_cacheLoad(cache, (size_t)(&xadj[vj+1])); + gk_cacheLoad(cache, (size_t)(&uxadj[vj])); + + if (xadj[vj+1]-uxadj[vj] == 0 || uxadj[vj] == xadj[vj]) + continue; + + /* hash Adj(vj) */ + gk_cacheLoad(cache, (size_t)(&uxadj[vj])); + gk_cacheLoad(cache, (size_t)(&xadj[vj+1])); + for (ej=uxadj[vj], ejend=xadj[vj+1]; ej<ejend; ej++) { + gk_cacheLoad(cache, (size_t)(&adjncy[ej])); + vk = adjncy[ej]; + for (l=(vk&hmsize); + gk_cacheLoad(cache, (size_t)(&hmap[l])) && hmap[l]!=0; + l=((l+1)&hmsize)); + hmap[l] = vk; + } + + /* find intersections */ + gk_cacheLoad(cache, (size_t)(&xadj[vj])); + gk_cacheLoad(cache, (size_t)(&uxadj[vj])); + for (ej=xadj[vj], ejend=uxadj[vj]; ej<ejend; ej++) { + gk_cacheLoad(cache, (size_t)(&adjncy[ej])); + gk_cacheLoad(cache, (size_t)(&uxadj[vi])); + vi = adjncy[ej]; + for (ei=uxadj[vi]; gk_cacheLoad(cache, (size_t)(&adjncy[ei])) && adjncy[ei]>vj; ei++) { + vk = adjncy[ei]; + for (l=vk&hmsize; + gk_cacheLoad(cache, (size_t)(&hmap[l])) && hmap[l]!=0 && hmap[l]!=vk; + l=((l+1)&hmsize)); + gk_cacheLoad(cache, (size_t)(&hmap[l])); + if (hmap[l] == vk) + ntriangles++; + } + } + + /* reset hash */ + gk_cacheLoad(cache, (size_t)(&uxadj[vj])); + gk_cacheLoad(cache, (size_t)(&xadj[vj+1])); + for (ej=uxadj[vj], ejend=xadj[vj+1]; ej<ejend; ej++) { + gk_cacheLoad(cache, (size_t)(&adjncy[ej])); + vk = adjncy[ej]; + for (l=(vk&hmsize); + gk_cacheLoad(cache, (size_t)(&hmap[l])) && hmap[l]!=vk; + l=((l+1)&hmsize)); + hmap[l] = 0; + } + } + printf("& compatible hmsize: %"PRId32" #triangles: %"PRIu64"\n", hmsize, ntriangles); + + gk_free((void **)&uxadj, &hmap, LTERM); + + //printf("%zd %zd\n", (ssize_t)cache->nhits, (ssize_t)cache->clock); + + double hitrate = gk_cacheGetHitRate(cache); + gk_cacheDestroy(&cache); + + return hitrate; +} + + +/*************************************************************************/ +/*! This function computes an increasing degree ordering +*/ +/*************************************************************************/ +int32_t *reorder_degrees(params_t *params, gk_graph_t *graph) +{ + int i, v, u, nvtxs, range; + ssize_t j, *xadj; + int32_t *counts, *perm; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + + for (range=0, i=0; i<nvtxs; i++) + range = gk_max(range, xadj[i+1]-xadj[i]); + range++; + + counts = gk_i32smalloc(range+1, 0, "counts"); + for (i=0; i<nvtxs; i++) + counts[xadj[i+1]-xadj[i]]++; + MAKECSR(i, range, counts); + + perm = gk_i32malloc(nvtxs, "perm"); + for (i=0; i<nvtxs; i++) + perm[i] = counts[xadj[i+1]-xadj[i]]++; + + gk_free((void **)&counts, LTERM); + + return perm; +} + + +/*************************************************************************/ +/*! This function re-orders the graph by: + - performing a fixed number of most-popular label propagation iterations + - locally renumbers the vertices with the same label +*/ +/*************************************************************************/ +int32_t *reorder_freqlpn(params_t *params, gk_graph_t *graph) +{ + int32_t i, ii, k, nvtxs, maxlbl; + ssize_t j, *xadj; + int32_t *adjncy, *labels, *freq, *perm; + gk_i32kv_t *cand; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels")); + freq = gk_i32smalloc(nvtxs, 0, "freq"); + perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm")); + + for (k=0; k<params->niter; k++) { + gk_i32randArrayPermuteFine(nvtxs, perm, 0); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + maxlbl = labels[adjncy[xadj[i]]]; + freq[maxlbl] = 1; + for (j=xadj[i]+1; j<xadj[i+1]; j++) { + freq[labels[adjncy[j]]]++; + if (freq[maxlbl] < freq[labels[adjncy[j]]]) + maxlbl = labels[adjncy[j]]; + else if (freq[maxlbl] == freq[labels[adjncy[j]]]) { + if (RandomInRange(2)) + maxlbl = labels[adjncy[j]]; + } + } + for (j=xadj[i]; j<xadj[i+1]; j++) + freq[labels[adjncy[j]]] = 0; + labels[i] = maxlbl; + } + } + + cand = gk_i32kvmalloc(nvtxs, "cand"); + for (i=0; i<nvtxs; i++) { + cand[i].key = labels[i]; + cand[i].val = i; + } + gk_i32kvsorti(nvtxs, cand); + + for (i=0; i<nvtxs; i++) + perm[cand[i].val] = i; + + gk_free((void **)&labels, &freq, &cand, LTERM); + + return perm; +} + + +/*************************************************************************/ +/*! This function re-orders the graph by: + - performing a fixed number of most-popular label propagation iterations + - restricts that propagation to take place within similar degree buckets + of vertices + - locally renumbers the vertices with the same label +*/ +/*************************************************************************/ +int32_t *reorder_freqlpn_db(params_t *params, gk_graph_t *graph) +{ + int32_t i, ii, k, nvtxs, maxlbl; + ssize_t j, *xadj; + int32_t *adjncy, *labels, *freq, *perm, *dbucket; + gk_i32kv_t *cand; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels")); + freq = gk_i32smalloc(nvtxs, 0, "freq"); + perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm")); + dbucket = gk_i32malloc(nvtxs, "dbucket"); + + for (i=0; i<nvtxs; i++) + dbucket[i] = ((xadj[i+1]-xadj[i])>>3); + + for (k=0; k<params->niter; k++) { + gk_i32randArrayPermuteFine(nvtxs, perm, 0); + for (ii=0; ii<nvtxs; ii++) { + i = perm[ii]; + maxlbl = labels[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (dbucket[i] != dbucket[adjncy[j]]) + continue; + + freq[labels[adjncy[j]]]++; + if (freq[maxlbl] < freq[labels[adjncy[j]]]) + maxlbl = labels[adjncy[j]]; + else if (freq[maxlbl] == freq[labels[adjncy[j]]]) { + if (RandomInRange(2)) + maxlbl = labels[adjncy[j]]; + } + } + for (j=xadj[i]; j<xadj[i+1]; j++) + freq[labels[adjncy[j]]] = 0; + labels[i] = maxlbl; + } + } + + cand = gk_i32kvmalloc(nvtxs, "cand"); + for (i=0; i<nvtxs; i++) { + cand[i].key = labels[i]; + cand[i].val = i; + } + gk_i32kvsorti(nvtxs, cand); + + for (i=0; i<nvtxs; i++) + perm[cand[i].val] = i; + + gk_free((void **)&labels, &freq, &dbucket, &cand, LTERM); + + return perm; +} + + +/*************************************************************************/ +/*! This function re-orders the graph by: + - performing a fixed number of min-label propagation iterations + - locally renumbers the vertices with the same label +*/ +/*************************************************************************/ +int32_t *reorder_minlpn(params_t *params, gk_graph_t *graph) +{ + int32_t i, ii, k, nvtxs, minlbl; + ssize_t j, *xadj; + int32_t *adjncy, *labels, *perm; + gk_i32kv_t *cand; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels")); + perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm")); + + for (k=0; k<params->niter; k++) { + for (i=0; i<nvtxs; i++) { + minlbl = labels[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (minlbl > labels[adjncy[j]]) + minlbl = labels[adjncy[j]]; + } + labels[i] = minlbl; + } + } + + cand = gk_i32kvmalloc(nvtxs, "cand"); + for (i=0; i<nvtxs; i++) { + cand[i].key = labels[i]; + cand[i].val = i; + } + gk_i32kvsorti(nvtxs, cand); + + for (i=0; i<nvtxs; i++) { + perm[cand[i].val] = i; + //if (i>0 && cand[i].key != cand[i-1].key) + // printf("%10d %10d\n", i-1, cand[i-1].key); + } + //printf("%10d %10d\n", i-1, cand[i-1].key); + + gk_free((void **)&labels, &cand, LTERM); + + return perm; +} + + +/*************************************************************************/ +/*! This function re-orders the graph by: + - performing a fixed number of min-label propagation iterations + - restricts that propagation to take place within similar degree buckets + of vertices + - locally renumbers the vertices with the same label +*/ +/*************************************************************************/ +int32_t *reorder_minlpn_db(params_t *params, gk_graph_t *graph) +{ + int32_t i, ii, k, nvtxs, minlbl; + ssize_t j, *xadj; + int32_t *adjncy, *labels, *perm, *dbucket; + gk_i32kv_t *cand; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + + labels = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "labels")); + perm = gk_i32incset(nvtxs, 0, gk_i32malloc(nvtxs, "perm")); + dbucket = gk_i32malloc(nvtxs, "dbucket"); + + for (i=0; i<nvtxs; i++) + dbucket[i] = ((xadj[i+1]-xadj[i])>>3); + + for (k=0; k<params->niter; k++) { + for (i=0; i<nvtxs; i++) { + minlbl = labels[i]; + for (j=xadj[i]; j<xadj[i+1]; j++) { + if (dbucket[i] != dbucket[adjncy[j]]) + continue; + + if (minlbl > labels[adjncy[j]]) + minlbl = labels[adjncy[j]]; + } + labels[i] = minlbl; + } + } + + cand = gk_i32kvmalloc(nvtxs, "cand"); + for (i=0; i<nvtxs; i++) { + cand[i].key = labels[i]; + cand[i].val = i; + } + gk_i32kvsorti(nvtxs, cand); + + for (i=0; i<nvtxs; i++) { + perm[cand[i].val] = i; + //if (i>0 && cand[i].key != cand[i-1].key) + // printf("%10d %10d\n", i-1, cand[i-1].key); + } + //printf("%10d %10d\n", i-1, cand[i-1].key); + + gk_free((void **)&labels, &dbucket, &cand, LTERM); + + return perm; +} + + +/*************************************************************************/ +/*! This function prints run parameters */ +/*************************************************************************/ +void print_init_info(params_t *params, gk_graph_t *graph) +{ + printf("*******************************************************************************\n"); + printf(" gkgraph\n\n"); + printf("Graph Information ----------------------------------------------------------\n"); + printf(" input file=%s, [%d, %zd]\n", + params->infile, graph->nvtxs, graph->xadj[graph->nvtxs]); + + printf("\n"); + printf("Options --------------------------------------------------------------------\n"); + printf(" lnbits=%d, cnbits=%d, type=%d, niter=%d, lamda=%f, eps=%e\n", + params->lnbits, params->cnbits, params->type, params->niter, + params->lamda, params->eps); + + printf("\n"); + printf("Working... -----------------------------------------------------------------\n"); +} + + +/*************************************************************************/ +/*! This function prints final statistics */ +/*************************************************************************/ +void print_final_info(params_t *params) +{ + printf("\n"); + printf("Memory Usage Information -----------------------------------------------------\n"); + printf(" Maximum memory used: %10zd bytes\n", (ssize_t) gk_GetMaxMemoryUsed()); + printf(" Current memory used: %10zd bytes\n", (ssize_t) gk_GetCurMemoryUsed()); + printf("********************************************************************************\n"); +} + + +/*************************************************************************/ +/*! This is the entry point of the command-line argument parser */ +/*************************************************************************/ +params_t *parse_cmdline(int argc, char *argv[]) +{ + int i; + int c, option_index; + params_t *params; + + params = (params_t *)gk_malloc(sizeof(params_t), "parse_cmdline: params"); + + /* initialize the params data structure */ + params->lnbits = 6; + params->cnbits = 13; + params->type = 1; + params->niter = 1; + params->eps = 1e-10; + params->lamda = 0.20; + params->nosort = 0; + params->write = 0; + params->infile = NULL; + + + /* Parse the command line arguments */ + while ((c = gk_getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { + switch (c) { + case CMD_LNBITS: + if (gk_optarg) params->lnbits = atoi(gk_optarg); + break; + case CMD_CNBITS: + if (gk_optarg) params->cnbits = atoi(gk_optarg); + break; + case CMD_TYPE: + if (gk_optarg) params->type = atoi(gk_optarg); + break; + case CMD_NITER: + if (gk_optarg) params->niter = atoi(gk_optarg); + break; + case CMD_EPS: + if (gk_optarg) params->eps = atof(gk_optarg); + break; + case CMD_LAMDA: + if (gk_optarg) params->lamda = atof(gk_optarg); + break; + case CMD_NOSORT: + params->nosort = 1; + break; + case CMD_WRITE: + params->write = 1; + break; + + case CMD_HELP: + for (i=0; strlen(helpstr[i]) > 0; i++) + printf("%s\n", helpstr[i]); + exit(0); + break; + case '?': + default: + printf("Illegal command-line option(s)\nUse %s -help for a summary of the options.\n", argv[0]); + exit(0); + } + } + + if (argc-gk_optind != 1) { + printf("Unrecognized parameters."); + for (i=0; strlen(shorthelpstr[i]) > 0; i++) + printf("%s\n", shorthelpstr[i]); + exit(0); + } + + params->infile = gk_strdup(argv[gk_optind++]); + + if (argc-gk_optind > 0) + params->outfile = gk_strdup(argv[gk_optind++]); + else + params->outfile = gk_strdup("gkgraph.out"); + + if (!gk_fexists(params->infile)) + errexit("input file %s does not exist.\n", params->infile); + + return params; +} + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/gksort.c b/3rdParty/metis/metis-5.1.1/GKlib/test/gksort.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/test/gksort.c rename to 3rdParty/metis/metis-5.1.1/GKlib/test/gksort.c diff --git a/3rdParty/metis/metis-5.1.1/GKlib/test/grKx.c b/3rdParty/metis/metis-5.1.1/GKlib/test/grKx.c new file mode 100644 index 0000000000000000000000000000000000000000..a72b5809261791e3f49629e7fb983fb9cb4c1009 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/grKx.c @@ -0,0 +1,256 @@ +/*! +\file +\brief A simple program to create multiple copies of an input matrix. + +\date 5/30/2013 +\author George +\version \verbatim $Id: grKx.c 17699 2014-09-27 18:05:31Z karypis $ \endverbatim +*/ + +#include <GKlib.h> + +/*************************************************************************/ +/*! Data structures for the code */ +/*************************************************************************/ +typedef struct { + int inf, outf; + int numbering; /* input numbering (output when applicable) */ + int readvals; /* input values (output when applicable) */ + int writevals; /* output values */ + int rshuf, cshuf; /* random shuffle of rows/columns */ + int symmetric; /* a symmetric shuffle */ + int ncopies; /* the copies of the graph to create */ + char *infile; /* input file */ + char *outfile; /* output file */ +} params_t; + + +/*************************************************************************/ +/*! Constants */ +/*************************************************************************/ +#define CMD_NUMONE 1 +#define CMD_NOREADVALS 2 +#define CMD_NOWRITEVALS 3 +#define CMD_RSHUF 4 +#define CMD_CSHUF 5 +#define CMD_SYMMETRIC 6 +#define CMD_HELP 100 + + +/*************************************************************************/ +/*! Local variables */ +/*************************************************************************/ +static struct gk_option long_options[] = { + {"numone", 0, 0, CMD_NUMONE}, + {"noreadvals", 0, 0, CMD_NOREADVALS}, + {"nowritevals", 0, 0, CMD_NOWRITEVALS}, + {"rshuf", 0, 0, CMD_RSHUF}, + {"cshuf", 0, 0, CMD_CSHUF}, + {"symmetric", 0, 0, CMD_SYMMETRIC}, + {"help", 0, 0, CMD_HELP}, + {0, 0, 0, 0} +}; + + +/*-------------------------------------------------------------------*/ +/* Mini help */ +/*-------------------------------------------------------------------*/ +static char helpstr[][100] = { +" ", +"Usage: grKx [options] <infile> <inf> <outfile> <outf> <ncopies>", +" ", +" Required parameters", +" infile, outfile", +" The name of the input/output CSR file.", +" ", +" inf/outf", +" The format of the input/output file.", +" Supported values are:", +" 1 GK_CSR_FMT_CLUTO", +" 2 GK_CSR_FMT_CSR", +" 3 GK_CSR_FMT_METIS", +" 4 GK_CSR_FMT_BINROW", +" 6 GK_CSR_FMT_IJV", +" 7 GK_CSR_FMT_BIJV", +" ", +" Optional parameters", +" -numone", +" Specifies that the numbering of the input file starts from 1. ", +" It only applies to CSR/IJV formats.", +" ", +" -nowritevals", +" Specifies that no values will be output.", +" ", +" -noreadvals", +" Specifies that the values will not be read when applicable.", +" ", +" -rshuf", +" Specifies that the rows will be randmly shuffled prior to output.", +" ", +" -cshuf", +" Specifies that the columns will be randmly shuffled prior to output.", +" ", +" -symmetric", +" Specifies that the row+column shuffling will be symmetric.", +" ", +" -help", +" Prints this message.", +"" +}; + +static char shorthelpstr[][100] = { +" ", +" Usage: grKx [options] <infile> <inf> <outfile> <outf> <ncopies>", +" use 'csrconv -help' for a summary of the options.", +"" +}; + + +/*************************************************************************/ +/*! This is the entry point of the command-line argument parser */ +/*************************************************************************/ +params_t *parse_cmdline(int argc, char *argv[]) +{ + int i; + int c, option_index; + params_t *params; + + params = (params_t *)gk_malloc(sizeof(params_t), "parse_cmdline: params"); + + /* initialize the params data structure */ + params->numbering = 0; + params->readvals = 1; + params->writevals = 1; + params->rshuf = 0; + params->cshuf = 0; + params->symmetric = 0; + + params->inf = -1; + params->outf = -1; + params->infile = NULL; + params->outfile = NULL; + + + /* Parse the command line arguments */ + while ((c = gk_getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { + switch (c) { + case CMD_NUMONE: + params->numbering = 1; + break; + case CMD_NOREADVALS: + params->readvals = 0; + break; + case CMD_NOWRITEVALS: + params->writevals = 0; + break; + case CMD_RSHUF: + params->rshuf = 1; + break; + case CMD_CSHUF: + params->cshuf = 1; + break; + case CMD_SYMMETRIC: + params->symmetric = 1; + break; + + case CMD_HELP: + for (i=0; strlen(helpstr[i]) > 0; i++) + printf("%s\n", helpstr[i]); + exit(0); + break; + case '?': + default: + printf("Illegal command-line option(s)\nUse %s -help for a summary of the options.\n", argv[0]); + exit(0); + } + } + + if (argc-gk_optind != 5) { + printf("Unrecognized parameters."); + for (i=0; strlen(shorthelpstr[i]) > 0; i++) + printf("%s\n", shorthelpstr[i]); + exit(0); + } + + params->infile = gk_strdup(argv[gk_optind++]); + params->inf = atoi(argv[gk_optind++]); + params->outfile = gk_strdup(argv[gk_optind++]); + params->outf = atoi(argv[gk_optind++]); + params->ncopies = atoi(argv[gk_optind++]); + + if (!gk_fexists(params->infile)) + errexit("input file %s does not exist.\n", params->infile); + + return params; +} + + +/*************************************************************************/ +/*! the entry point */ +/**************************************************************************/ +int main(int argc, char *argv[]) +{ + ssize_t i, j, k, knnz, nrows, ncols, ncopies; + int what; + params_t *params; + gk_csr_t *mat, *kmat, *smat; + + /* get command-line options */ + params = parse_cmdline(argc, argv); + + /* read the data */ + mat = gk_csr_Read(params->infile, params->inf, params->readvals, params->numbering); + + /* create the copies */ + ncopies = params->ncopies; + + nrows = mat->nrows; + ncols = mat->ncols; + knnz = mat->rowptr[nrows]*ncopies; + + kmat = gk_csr_Create(); + kmat->nrows = nrows*ncopies; + kmat->ncols = ncols*ncopies; + kmat->rowptr = gk_zmalloc(kmat->nrows+1, "rowptr"); + kmat->rowind = gk_imalloc(knnz, "rowind"); + if (mat->rowval) + kmat->rowval = gk_fmalloc(knnz, "rowval"); + + kmat->rowptr[0] = knnz = 0; + for (k=0; k<ncopies; k++) { + for (i=0; i<nrows; i++) { + for (j=mat->rowptr[i]; j<mat->rowptr[i+1]; j++, knnz++) { + kmat->rowind[knnz] = mat->rowind[j] + k*ncols; + if (mat->rowval) + kmat->rowval[knnz] = mat->rowval[j]; + } + kmat->rowptr[k*nrows+i+1] = knnz; + } + } + + gk_csr_Free(&mat); + mat = kmat; + + + if (params->rshuf || params->cshuf) { + if (params->rshuf && params->cshuf) + what = GK_CSR_ROWCOL; + else if (params->rshuf) + what = GK_CSR_ROW; + else + what = GK_CSR_COL; + + smat = gk_csr_Shuffle(mat, what, params->symmetric); + gk_csr_Free(&mat); + mat = smat; + } + + if (params->writevals && mat->rowval == NULL) + mat->rowval = gk_fsmalloc(mat->rowptr[mat->nrows], 1.0, "mat->rowval"); + + gk_csr_Write(mat, params->outfile, params->outf, params->writevals, 0); + + gk_csr_Free(&mat); + +} + diff --git a/3rdParty/metis/metis-5.1.1/GKlib/test/m2mnbrs.c b/3rdParty/metis/metis-5.1.1/GKlib/test/m2mnbrs.c new file mode 100644 index 0000000000000000000000000000000000000000..53f35caea96acf17de937f8c4a075d95881f2355 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/m2mnbrs.c @@ -0,0 +1,304 @@ +/*! +\file +\brief It takes as input two CSR matrices and finds for each row of the + first matrix the most similar rows in the second matrix. + +\date 9/27/2014 +\author George +\version \verbatim $Id: m2mnbrs.c 17699 2014-09-27 18:05:31Z karypis $ \endverbatim +*/ + +#include <GKlib.h> + +/*************************************************************************/ +/*! Data structures for the code */ +/*************************************************************************/ +typedef struct { + int simtype; /*!< The similarity type to use */ + int nnbrs; /*!< The maximum number of nearest neighbots to output */ + float minsim; /*!< The minimum similarity to use for keeping neighbors */ + + int verbosity; /*!< The reporting verbosity level */ + + char *qfile; /*!< The file storing the query documents */ + char *cfile; /*!< The file storing the collection documents */ + char *outfile; /*!< The file where the output will be stored */ + + /* timers */ + double timer_global; + double timer_1; + double timer_2; + double timer_3; + double timer_4; +} params_t; + + +/*************************************************************************/ +/*! Constants */ +/*************************************************************************/ +/* Versions */ +#define VER_MAJOR 0 +#define VER_MINOR 1 +#define VER_SUBMINOR 0 + +/* Command-line option codes */ +#define CMD_SIMTYPE 10 +#define CMD_NNBRS 20 +#define CMD_MINSIM 22 +#define CMD_VERBOSITY 70 +#define CMD_HELP 100 + +/* The text labels for the different simtypes */ +static char simtypenames[][10] = {"", "dotp", "cos", "jac", ""}; + + + +/*************************************************************************/ +/*! Local variables */ +/*************************************************************************/ +static struct gk_option long_options[] = { + {"simtype", 1, 0, CMD_SIMTYPE}, + {"nnbrs", 1, 0, CMD_NNBRS}, + {"minsim", 1, 0, CMD_MINSIM}, + {"verbosity", 1, 0, CMD_VERBOSITY}, + + {"help", 0, 0, CMD_HELP}, + {0, 0, 0, 0} +}; + +static gk_StringMap_t simtype_options[] = { + {"cos", GK_CSR_COS}, + {"jac", GK_CSR_JAC}, + {NULL, 0} +}; + + +/*------------------------------------------------------------------- + * Mini help + *-------------------------------------------------------------------*/ +static char helpstr[][100] = +{ +" ", +"Usage: m2mnbrs [options] qfile cfile [outfile]", +" ", +" Options", +" -simtype=string", +" Specifies the type of similarity to use. Possible values are:", +" cos - Cosine similarity", +" jac - Jacquard similarity [default]", +" ", +" -nnbrs=int", +" Specifies the maximum number of nearest neighbors.", +" A value of -1 indicates that all neighbors will be considered.", +" Default value is 100.", +" ", +" -minsim=float", +" The minimum allowed similarity between neighbors. ", +" Default value is .25.", +" ", +" -verbosity=int", +" Specifies the level of debugging information to be displayed.", +" Default value is 0.", +" ", +" -help", +" Prints this message.", +"" +}; + + + +/*************************************************************************/ +/*! Function prototypes */ +/*************************************************************************/ +params_t *parse_cmdline(int argc, char *argv[]); +void FindNeighbors(params_t *params, gk_csr_t *qmat, gk_csr_t *cmat); + + +/*************************************************************************/ +/*! This is the entry point of the command-line argument parser */ +/*************************************************************************/ +params_t *parse_cmdline(int argc, char *argv[]) +{ + int i; + int c, option_index; + params_t *params; + + params = (params_t *)gk_malloc(sizeof(params_t), "parse_cmdline: params"); + + /* initialize the params data structure */ + params->simtype = GK_CSR_JAC; + params->nnbrs = 100; + params->minsim = .25; + params->verbosity = -1; + params->qfile = NULL; + params->cfile = NULL; + params->outfile = NULL; + + + /* Parse the command line arguments */ + while ((c = gk_getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) { + switch (c) { + case CMD_SIMTYPE: + if (gk_optarg) { + if ((params->simtype = gk_GetStringID(simtype_options, gk_optarg)) == -1) + errexit("Invalid simtype of %s.\n", gk_optarg); + } + break; + + case CMD_NNBRS: + if (gk_optarg) params->nnbrs = atoi(gk_optarg); + break; + + case CMD_MINSIM: + if (gk_optarg) params->minsim = atof(gk_optarg); + break; + + case CMD_VERBOSITY: + if (gk_optarg) params->verbosity = atoi(gk_optarg); + break; + + case CMD_HELP: + for (i=0; strlen(helpstr[i]) > 0; i++) + printf("%s\n", helpstr[i]); + exit(EXIT_SUCCESS); + break; + + case '?': + default: + printf("Illegal command-line option(s)\nUse %s -help for a summary of the options.\n", argv[0]); + exit(EXIT_FAILURE); + } + } + + /* Get the input/output file info */ + if (argc-gk_optind < 1) { + printf("Missing input/output file info.\n Use %s -help for a summary of the options.\n", argv[0]); + exit(EXIT_FAILURE); + } + + params->qfile = gk_strdup(argv[gk_optind++]); + params->cfile = gk_strdup(argv[gk_optind++]); + params->outfile = (gk_optind < argc ? gk_strdup(argv[gk_optind++]) : NULL); + + if (!gk_fexists(params->qfile)) + errexit("input file %s does not exist.\n", params->qfile); + if (!gk_fexists(params->cfile)) + errexit("input file %s does not exist.\n", params->cfile); + + return params; +} + + +/*************************************************************************/ +/*! This is the entry point of the program */ +/**************************************************************************/ +int main(int argc, char *argv[]) +{ + params_t *params; + gk_csr_t *qmat, *cmat; + int rc = EXIT_SUCCESS; + + params = parse_cmdline(argc, argv); + + qmat = gk_csr_Read(params->qfile, GK_CSR_FMT_CSR, 1, 0); + cmat = gk_csr_Read(params->cfile, GK_CSR_FMT_CSR, 1, 0); + + + printf("********************************************************************************\n"); + printf("sd (%d.%d.%d) Copyright 2014, GK.\n", VER_MAJOR, VER_MINOR, VER_SUBMINOR); + printf(" simtype=%s, nnbrs=%d, minsim=%.2f\n", + simtypenames[params->simtype], params->nnbrs, params->minsim); + printf(" qfile=%s, nrows=%d, ncols=%d, nnz=%zd\n", + params->qfile, qmat->nrows, qmat->ncols, qmat->rowptr[qmat->nrows]); + printf(" cfile=%s, nrows=%d, ncols=%d, nnz=%zd\n", + params->cfile, cmat->nrows, cmat->ncols, cmat->rowptr[cmat->nrows]); + + gk_clearwctimer(params->timer_global); + gk_clearwctimer(params->timer_1); + gk_clearwctimer(params->timer_2); + gk_clearwctimer(params->timer_3); + gk_clearwctimer(params->timer_4); + + gk_startwctimer(params->timer_global); + + FindNeighbors(params, qmat, cmat); + + gk_stopwctimer(params->timer_global); + + printf(" wclock: %.2lfs\n", gk_getwctimer(params->timer_global)); + printf(" timer1: %.2lfs\n", gk_getwctimer(params->timer_1)); + printf(" timer2: %.2lfs\n", gk_getwctimer(params->timer_2)); + printf(" timer3: %.2lfs\n", gk_getwctimer(params->timer_3)); + printf(" timer4: %.2lfs\n", gk_getwctimer(params->timer_4)); + printf("********************************************************************************\n"); + + gk_csr_Free(&qmat); + gk_csr_Free(&cmat); + + exit(rc); +} + + +/*************************************************************************/ +/*! Reads and computes the neighbors of each query document against the + collection of documents */ +/**************************************************************************/ +void FindNeighbors(params_t *params, gk_csr_t *qmat, gk_csr_t *cmat) +{ + int iQ, iH, nhits; + int32_t *marker; + gk_fkv_t *hits, *cand; + FILE *fpout; + + GKASSERT(qmat->ncols <= cmat->ncols); + + /* if cosine, make rows unit length */ + if (params->simtype == GK_CSR_COS) { + gk_csr_Normalize(qmat, GK_CSR_ROW, 2); + gk_csr_Normalize(cmat, GK_CSR_ROW, 2); + } + + /* create the inverted index */ + gk_csr_CreateIndex(cmat, GK_CSR_COL); + + /* compute the row norms */ + gk_csr_ComputeSquaredNorms(cmat, GK_CSR_ROW); + + /* create the output file */ + fpout = (params->outfile ? gk_fopen(params->outfile, "w", "FindNeighbors: fpout") : NULL); + + /* allocate memory for the necessary working arrays */ + hits = gk_fkvmalloc(cmat->nrows, "FindNeighbors: hits"); + marker = gk_i32smalloc(cmat->nrows, -1, "FindNeighbors: marker"); + cand = gk_fkvmalloc(cmat->nrows, "FindNeighbors: cand"); + + + /* find the best neighbors for each query document */ + gk_startwctimer(params->timer_1); + for (iQ=0; iQ<qmat->nrows; iQ++) { + if (params->verbosity > 0) + printf("Working on query %7d\n", iQ); + + /* find the neighbors of the ith document */ + nhits = gk_csr_GetSimilarRows(cmat, + qmat->rowptr[iQ+1]-qmat->rowptr[iQ], + qmat->rowind+qmat->rowptr[iQ], + qmat->rowval+qmat->rowptr[iQ], + params->simtype, params->nnbrs, params->minsim, + hits, marker, cand); + + /* write the results in the file */ + if (fpout) { + for (iH=0; iH<nhits; iH++) + fprintf(fpout, "%8d %8zd %.3f\n", iQ, hits[iH].val, hits[iH].key); + } + } + gk_stopwctimer(params->timer_1); + + + /* cleanup and exit */ + if (fpout) gk_fclose(fpout); + + gk_free((void **)&hits, &marker, &cand, LTERM); +} + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/rw.c b/3rdParty/metis/metis-5.1.1/GKlib/test/rw.c similarity index 98% rename from 3rdParty/metis/metis-5.1.0/GKlib/test/rw.c rename to 3rdParty/metis/metis-5.1.1/GKlib/test/rw.c index e338f89ddd2fd7bf8e975299f7099fc72abb27ea..1a3295ee741e673722919b4b34625e7952a0b96f 100644 --- a/3rdParty/metis/metis-5.1.0/GKlib/test/rw.c +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/rw.c @@ -1,10 +1,10 @@ /*! \file -\brief A simple frequent itemset discovery program to test GKlib's routines +\brief A simple (personalized) random walk program to test GKlib's routines \date 6/12/2008 \author George -\version \verbatim $Id: rw.c 11387 2012-01-21 23:36:23Z karypis $ \endverbatim +\version \verbatim $Id$ \endverbatim */ #include <GKlib.h> @@ -117,7 +117,6 @@ int main(int argc, char *argv[]) print_init_info(params, mat); - if (params->ntvs != -1) { /* compute the pr for different randomly generated restart-distribution vectors */ float **prs; diff --git a/3rdParty/metis/metis-5.1.1/GKlib/test/splatt2svd.c b/3rdParty/metis/metis-5.1.1/GKlib/test/splatt2svd.c new file mode 100644 index 0000000000000000000000000000000000000000..111d31c94bba2231689b930863edf4f2c3d12f0f --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/test/splatt2svd.c @@ -0,0 +1,98 @@ +/*! +\file +\brief A simple program to convert a tensor in coordinate format into an unfolded + matrix + +\author George +*/ + +#include <GKlib.h> + + +int main(int argc, char *argv[]) +{ + size_t nnz, i, j, k, nI, nJ, nK, nrows, ncols; + int32_t *I, *J, *K, *rowind, *colind; + ssize_t *rowptr, *colptr; + float *V, *rowval, *colval; + + if (argc != 2) + errexit("Usage %s <infile> [%d]\n", argv[0], argc); + + if (!gk_fexists(argv[1])) + errexit("File %s does not exist.\n", argv[1]); + + gk_getfilestats(argv[1], &nnz, NULL, NULL, NULL); + I = gk_i32malloc(nnz, "I"); + J = gk_i32malloc(nnz, "J"); + K = gk_i32malloc(nnz, "K"); + V = gk_fmalloc(nnz, "V"); + + fprintf(stderr, "Input nnz: %zd\n", nnz); + + FILE *fpin = gk_fopen(argv[1], "r", "infile"); + for (i=0; i<nnz; i++) { + if (4 != fscanf(fpin, "%d %d %d %f", K+i, I+i, J+i, V+i)) + errexit("Failed to read 4 values in line %zd\n", i); + K[i]--; I[i]--; J[i]--; + } + gk_fclose(fpin); + + nI = gk_i32max(nnz, I, 1)+1; + nJ = gk_i32max(nnz, J, 1)+1; + nK = gk_i32max(nnz, K, 1)+1; + + fprintf(stderr, "nI: %zd, nJ: %zd, nK: %zd\n", nI, nJ, nK); + + nrows = nK*nI; + ncols = nJ; + rowptr = gk_zsmalloc(nrows+1, 0, "rowptr"); + for (i=0; i<nnz; i++) + rowptr[K[i]*nI+I[i]]++; + MAKECSR(i, nrows, rowptr); + + rowind = gk_i32malloc(nnz, "rowind"); + rowval = gk_fmalloc(nnz, "rowval"); + for (i=0; i<nnz; i++) { + rowind[rowptr[K[i]*nI+I[i]]] = J[i]; + rowval[rowptr[K[i]*nI+I[i]]] = V[i]; + rowptr[K[i]*nI+I[i]]++; + } + SHIFTCSR(i, nrows, rowptr); + + gk_free((void **)&I, &J, &K, &V, LTERM); + + colptr = gk_zsmalloc(ncols+1, 0, "colptr"); + colind = gk_i32malloc(nnz, "colind"); + colval = gk_fmalloc(nnz, "colval"); + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) + colptr[rowind[j]]++; + } + MAKECSR(i, ncols, colptr); + for (i=0; i<nrows; i++) { + for (j=rowptr[i]; j<rowptr[i+1]; j++) { + colind[colptr[rowind[j]]] = i; + colval[colptr[rowind[j]]] = rowval[j]; + colptr[rowind[j]]++; + } + } + SHIFTCSR(i, ncols, colptr); + + /* sanity check */ + for (i=0; i<ncols; i++) { + for (j=colptr[i]+1; j<colptr[i+1]; j++) { + if (colind[j-1] == colind[j]) + fprintf(stderr, "Duplicate row indices: %d %d %d\n", (int)i, colind[j], colind[j-1]); + } + } + + printf("%zd %zd %zd\n", nrows, ncols, nnz); + for (i=0; i<ncols; i++) { + printf("%zd\n", colptr[i+1]-colptr[i]); + for (j=colptr[i]; j<colptr[i+1]; j++) + printf("%d %.3f\n", colind[j], colval[j]); + } + +} + diff --git a/3rdParty/metis/metis-5.1.0/GKlib/test/strings.c b/3rdParty/metis/metis-5.1.1/GKlib/test/strings.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/test/strings.c rename to 3rdParty/metis/metis-5.1.1/GKlib/test/strings.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/timers.c b/3rdParty/metis/metis-5.1.1/GKlib/timers.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/timers.c rename to 3rdParty/metis/metis-5.1.1/GKlib/timers.c diff --git a/3rdParty/metis/metis-5.1.0/GKlib/tokenizer.c b/3rdParty/metis/metis-5.1.1/GKlib/tokenizer.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/GKlib/tokenizer.c rename to 3rdParty/metis/metis-5.1.1/GKlib/tokenizer.c diff --git a/3rdParty/metis/metis-5.1.1/GKlib/win32/adapt.c b/3rdParty/metis/metis-5.1.1/GKlib/win32/adapt.c new file mode 100644 index 0000000000000000000000000000000000000000..546857c54183b48252256b01633c74472456accf --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/win32/adapt.c @@ -0,0 +1,11 @@ +/* +\file win32/adapt.c +\brief Implementation of Win32 adaptation of libc functions +*/ + +#include "adapt.h" + +pid_t getpid(void) +{ + return GetCurrentProcessId(); +} diff --git a/3rdParty/metis/metis-5.1.1/GKlib/win32/adapt.h b/3rdParty/metis/metis-5.1.1/GKlib/win32/adapt.h new file mode 100644 index 0000000000000000000000000000000000000000..35e60ed604c239524a6541caa58b76ec38d82a92 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/GKlib/win32/adapt.h @@ -0,0 +1,14 @@ +/* +\file win32/adapt.h +\brief Declaration of Win32 adaptation of POSIX functions and types +*/ +#ifndef _WIN32_ADAPT_H_ +#define _WIN32_ADAPT_H_ + +#include <windows.h> + +typedef DWORD pid_t; + +pid_t getpid(void); + +#endif /* _WIN32_ADAPT_H_ */ diff --git a/3rdParty/metis/metis-5.1.1/LICENSE b/3rdParty/metis/metis-5.1.1/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..3a098eb2889bd7354d5a00d62cff00e54ee55399 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/LICENSE @@ -0,0 +1,19 @@ + +Copyright & License Notice +--------------------------- + +Copyright 1995-2013, Regents of the University of Minnesota + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +implied. See the License for the specific language governing +permissions and limitations under the License. + + \ No newline at end of file diff --git a/3rdParty/metis/metis-5.1.1/README.md b/3rdParty/metis/metis-5.1.1/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8c887359105656fa4efbfe5680de252961707079 --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/README.md @@ -0,0 +1,171 @@ +# METIS + +METIS is a set of serial programs for partitioning graphs, partitioning finite element meshes, +and producing fill reducing orderings for sparse matrices. The algorithms implemented in +METIS are based on the multilevel recursive-bisection, multilevel k-way, and multi-constraint +partitioning schemes developed in our lab. + +## Downloading METIS + +METIS uses Git submodules to manage external dependencies. Hence, please specify the `--recursive` option while cloning the repo as follow: +``` +git clone --recursive https://github.com/KarypisLab/METIS.git +``` + +## Building standalone METIS binaries and library + +To build METIS you can follow the instructions below: + +### Dependencies + +General dependencies for building slim are: gcc, cmake, build-essential. +In Ubuntu systems these can be obtained from the apt package manager (e.g., apt-get install cmake, etc) + +``` +sudo apt-get install build-essential +sudo apt-get install cmake +``` + +### Building and installing METIS + +METIS is primarily configured by passing options to make config. For example: + +``` +make config shared=1 cc=gcc prefix=~/local +make install +``` + +will configure metis to be built as a shared library using GCC and then install the binaries, header files, and libraries at + +``` +~/local/bin +~/local/include +~/local/lib +``` + +directories, respectively. + +### Common configuration options are: + + cc=[compiler] - The C compiler to use [default is determined by CMake] + shared=1 - Build a shared library instead of a static one [off by default] + prefix=[PATH] - Set the installation prefix [~/local by default] + i64=1 - Sets to 64 bits the width of the datatype that will store information + about the vertices and their adjacency lists. + r64=1 - Sets to 64 bits the width of the datatype that will store information + about floating point numbers. + +### Advanced debugging related options: + + gdb=1 - Build with support for GDB [off by default] + debug=1 - Enable debugging support [off by default] + assert=1 - Enable asserts [off by default] + assert2=1 - Enable very expensive asserts [off by default] + +### Other make commands + + make uninstall + Removes all files installed by 'make install'. + + make clean + Removes all object files but retains the configuration options. + + make distclean + Performs clean and completely removes the build directory. + + +<!--- +## Getting started + +Here are some examples to quickly try out SLIM on the sample datasets that are provided with SLIM. + +### Python interface + +```python +import pandas as pd +from SLIM import SLIM, SLIMatrix + +#read training data stored as triplets <user> <item> <rating> +traindata = pd.read_csv('../test/AutomotiveTrain.ijv', delimiter = ' ', header=None) +trainmat = SLIMatrix(traindata) + +#set up parameters to learn model, e.g., use Coordinate Descent with L1 and L2 +#regularization +params = {'algo':'cd', 'nthreads':2, 'l1r':1.0, 'l2r':1.0} + +#learn the model using training data and desired parameters +model = SLIM() +model.train(params, trainmat) + +#read test data having candidate items for users +testdata = pd.read_csv('../test/AutomotiveTest.ijv', delimiter = ' ', header=None) +#NOTE: model object is passed as an argument while generating test matrix +testmat = SLIMatrix(testdata, model) + +#generate top-10 recommendations +prediction_res = model.predict(testmat, nrcmds=10, outfile = 'output.txt') + +#dump the model to files on disk +model.save_model(modelfname='model.csr', # filename to save the model as a csr matrix + mapfname='map.csr' # filename to save the item map + ) + +#load the model from from disk +model_new = SLIM() +model_new.load_model(modelfname='model.csr', # filename of the model + mapfname='map.csr' # filename of the item map + ) +``` + +The users can also refer to the python notebook [UserGuide.ipynb](./python-package/UserGuide.ipynb) located at +`./python-package/UserGuide.ipynb` for more examples on using the python api. + +### Command-line programs +SLIM can be used by running the command-line programs that are located under `./build` directory. Specifically, SLIM provides the following three command-line programs: +- `slim_learn`: for estimating a model +- `slim_predict`: for applying a previously estimated model, and +- `slim_mselect`: for exploring a set of hyper-parameters in order to select the best performing model. + +Additional information about how to use these command-line programs is located in +SLIM's reference manual that is available at +[./doxygen/html/index.html](http://glaros.dtc.umn.edu/gkhome/files/fs/sw/slim/doc/html/index.html) +or +[./doxygen/latex/refman.pdf](http://glaros.dtc.umn.edu/gkhome/files/fs/sw/slim/doc/refman.pdf). + +### Library interface + +You can also use SLIM by direclty linking into your C/C++ program via its library interface. SLIM's API is described +in SLIM's reference manual (see links above). + +## Citing +If you use any part of this library in your research, please cite it using the +following BibTex entry: + +``` +@online{slim, + title = {{SLIM Library for Recommender Systems}}, + author = {Ning, Xia and Nikolakopoulos, Athanasios N. and Shui, Zeren and Sharma, Mohit and Karypis, George}, + url = {https://github.com/KarypisLab/SLIM}, + year = {2019}, +} +``` + +## References +1. [Slim: Sparse linear methods for top-n recommender systems](http://glaros.dtc.umn.edu/gkhome/node/774) +## Credits & Contact Information + +This implementation of SLIM was written by George Karypis with contributions by Xia Ning, Athanasios N. Nikolakopoulos, Zeren Shui and Mohit Sharma. + +If you encounter any problems or have any suggestions, please contact George Karypis at <a href="mailto:karypis@umn.edu">karypis@umn.edu</a>. + +--> + +## Copyright & License Notice +Copyright 1998-2020, Regents of the University of Minnesota + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + diff --git a/3rdParty/metis/metis-5.1.0/include/CMakeLists.txt b/3rdParty/metis/metis-5.1.1/include/CMakeLists.txt similarity index 100% rename from 3rdParty/metis/metis-5.1.0/include/CMakeLists.txt rename to 3rdParty/metis/metis-5.1.1/include/CMakeLists.txt diff --git a/3rdParty/metis/metis-5.1.0/include/metis.h b/3rdParty/metis/metis-5.1.1/include/metis.h similarity index 97% rename from 3rdParty/metis/metis-5.1.0/include/metis.h rename to 3rdParty/metis/metis-5.1.1/include/metis.h index dc5406ae546e532398b6d682e9a34de8cf457541..90f5163c1d96ad05b78c9033904e327db6706ec3 100644 --- a/3rdParty/metis/metis-5.1.0/include/metis.h +++ b/3rdParty/metis/metis-5.1.1/include/metis.h @@ -30,7 +30,7 @@ GCC does provides these definitions in stdint.h, but it may require some modifications on other architectures. --------------------------------------------------------------------------*/ -#define IDXTYPEWIDTH 32 +//#define IDXTYPEWIDTH 32 /*-------------------------------------------------------------------------- @@ -40,7 +40,7 @@ 32 : single precission floating point (float) 64 : double precission floating point (double) --------------------------------------------------------------------------*/ -#define REALTYPEWIDTH 32 +//#define REALTYPEWIDTH 32 @@ -228,6 +228,11 @@ METIS_API(int) METIS_NodeRefine(idx_t nvtxs, idx_t *xadj, idx_t *vwgt, idx_t *ad idx_t *where, idx_t *hmarker, real_t ubfactor); +/* These functions are used by DGL */ + +METIS_API(int) METIS_CacheFriendlyReordering(idx_t nvtxs, idx_t *xadj, idx_t *adjncy, + idx_t *part, idx_t *old2new); + #ifdef __cplusplus } #endif @@ -262,10 +267,12 @@ typedef enum { METIS_OPTION_IPTYPE, METIS_OPTION_RTYPE, METIS_OPTION_DBGLVL, + METIS_OPTION_NIPARTS, METIS_OPTION_NITER, METIS_OPTION_NCUTS, METIS_OPTION_SEED, METIS_OPTION_NO2HOP, + METIS_OPTION_ONDISK, METIS_OPTION_MINCONN, METIS_OPTION_CONTIG, METIS_OPTION_COMPRESS, @@ -274,6 +281,7 @@ typedef enum { METIS_OPTION_NSEPS, METIS_OPTION_UFACTOR, METIS_OPTION_NUMBERING, + METIS_OPTION_DROPEDGES, /* Used for command-line parameter purposes */ METIS_OPTION_HELP, diff --git a/3rdParty/metis/metis-5.1.0/libmetis/CMakeLists.txt b/3rdParty/metis/metis-5.1.1/libmetis/CMakeLists.txt similarity index 85% rename from 3rdParty/metis/metis-5.1.0/libmetis/CMakeLists.txt rename to 3rdParty/metis/metis-5.1.1/libmetis/CMakeLists.txt index bbe23b67cfde13070befdf167479039b8f602aa8..85f96b08a0b224e9dccf463e397b562c23292a1b 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/CMakeLists.txt +++ b/3rdParty/metis/metis-5.1.1/libmetis/CMakeLists.txt @@ -1,11 +1,9 @@ # Add this directory for internal users. -include_directories(.) +#include_directories(.) # Find sources. file(GLOB metis_sources *.c) # Build libmetis. add_library(metis ${METIS_LIBRARY_TYPE} ${GKlib_sources} ${metis_sources}) -groupTarget(metis ${thirdPartyFolder}) - if(UNIX) target_link_libraries(metis m) endif() diff --git a/3rdParty/metis/metis-5.1.0/libmetis/auxapi.c b/3rdParty/metis/metis-5.1.1/libmetis/auxapi.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/auxapi.c rename to 3rdParty/metis/metis-5.1.1/libmetis/auxapi.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/balance.c b/3rdParty/metis/metis-5.1.1/libmetis/balance.c similarity index 99% rename from 3rdParty/metis/metis-5.1.0/libmetis/balance.c rename to 3rdParty/metis/metis-5.1.1/libmetis/balance.c index 3fb0e6e56a42bf13b2fa19b5fde4d93a3817ceff..6e88b53237f8389a589821ddc515d596446b3034 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/balance.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/balance.c @@ -20,7 +20,7 @@ void Balance2Way(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts) if (graph->ncon == 1) { /* return right away if the balance is OK */ - if (iabs(ntpwgts[0]*graph->tvwgt[0]-graph->pwgts[0]) < 3*graph->tvwgt[0]/graph->nvtxs) + if (rabs(ntpwgts[0]*graph->tvwgt[0]-graph->pwgts[0]) < 3*graph->tvwgt[0]/graph->nvtxs) return; if (graph->nbnd > 0) diff --git a/3rdParty/metis/metis-5.1.0/libmetis/bucketsort.c b/3rdParty/metis/metis-5.1.1/libmetis/bucketsort.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/bucketsort.c rename to 3rdParty/metis/metis-5.1.1/libmetis/bucketsort.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/checkgraph.c b/3rdParty/metis/metis-5.1.1/libmetis/checkgraph.c similarity index 91% rename from 3rdParty/metis/metis-5.1.0/libmetis/checkgraph.c rename to 3rdParty/metis/metis-5.1.1/libmetis/checkgraph.c index 852634614c9a757313ff19f5c868f87da5b3d630..fd4b38e7623669f684a598277c2cf9ab298f827f 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/checkgraph.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/checkgraph.c @@ -43,12 +43,11 @@ int CheckGraph(graph_t *graph, int numflag, int verbose) adjncy = graph->adjncy; adjwgt = graph->adjwgt; - ASSERT(adjwgt != NULL); - htable = ismalloc(nvtxs, 0, "htable"); minedge = maxedge = adjncy[0]; - minewgt = maxewgt = adjwgt[0]; + if (adjwgt) + minewgt = maxewgt = adjwgt[0]; for (i=0; i<nvtxs; i++) { for (j=xadj[i]; j<xadj[i+1]; j++) { @@ -56,8 +55,10 @@ int CheckGraph(graph_t *graph, int numflag, int verbose) minedge = (k < minedge) ? k : minedge; maxedge = (k > maxedge) ? k : maxedge; - minewgt = (adjwgt[j] < minewgt) ? adjwgt[j] : minewgt; - maxewgt = (adjwgt[j] > maxewgt) ? adjwgt[j] : maxewgt; + if (adjwgt) { + minewgt = (adjwgt[j] < minewgt) ? adjwgt[j] : minewgt; + maxewgt = (adjwgt[j] > maxewgt) ? adjwgt[j] : maxewgt; + } if (i == k) { if (verbose) @@ -68,14 +69,16 @@ int CheckGraph(graph_t *graph, int numflag, int verbose) else { for (l=xadj[k]; l<xadj[k+1]; l++) { if (adjncy[l] == i) { - if (adjwgt[l] != adjwgt[j]) { - if (verbose) - printf("Edges (u:%"PRIDX" v:%"PRIDX" wgt:%"PRIDX") and " - "(v:%"PRIDX" u:%"PRIDX" wgt:%"PRIDX") " - "do not have the same weight!\n", - i+numflag, k+numflag, adjwgt[j], - k+numflag, i+numflag, adjwgt[l]); - err++; + if (adjwgt) { + if (adjwgt[l] != adjwgt[j]) { + if (verbose) + printf("Edges (u:%"PRIDX" v:%"PRIDX" wgt:%"PRIDX") and " + "(v:%"PRIDX" u:%"PRIDX" wgt:%"PRIDX") " + "do not have the same weight!\n", + i+numflag, k+numflag, adjwgt[j], + k+numflag, i+numflag, adjwgt[l]); + err++; + } } break; } diff --git a/3rdParty/metis/metis-5.1.0/libmetis/coarsen.c b/3rdParty/metis/metis-5.1.1/libmetis/coarsen.c similarity index 55% rename from 3rdParty/metis/metis-5.1.0/libmetis/coarsen.c rename to 3rdParty/metis/metis-5.1.1/libmetis/coarsen.c index 165344e6ef6dceff70359191ac621344d623c46f..447fc43e8974c9dc3269fc3f5a17a24045c8e14d 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/coarsen.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/coarsen.c @@ -5,7 +5,7 @@ \date Started 7/23/97 \author George \author Copyright 1997-2011, Regents of the University of Minnesota -\version\verbatim $Id: coarsen.c 13936 2013-03-30 03:59:09Z karypis $ \endverbatim +\version\verbatim $Id: coarsen.c 20398 2016-11-22 17:17:12Z karypis $ \endverbatim */ @@ -60,6 +60,8 @@ graph_t *CoarsenGraph(ctrl_t *ctrl, graph_t *graph) gk_errexit(SIGERR, "Unknown ctype: %d\n", ctrl->ctype); } + graph_WriteToDisk(ctrl, graph); + graph = graph->coarser; eqewgts = 0; level++; @@ -123,6 +125,8 @@ graph_t *CoarsenGraphNlevels(ctrl_t *ctrl, graph_t *graph, idx_t nlevels) gk_errexit(SIGERR, "Unknown ctype: %d\n", ctrl->ctype); } + graph_WriteToDisk(ctrl, graph); + graph = graph->coarser; eqewgts = 0; @@ -148,9 +152,10 @@ graph_t *CoarsenGraphNlevels(ctrl_t *ctrl, graph_t *graph, idx_t nlevels) /**************************************************************************/ idx_t Match_RM(ctrl_t *ctrl, graph_t *graph) { - idx_t i, pi, ii, j, jj, jjinc, k, nvtxs, ncon, cnvtxs, maxidx, last_unmatched; + idx_t i, pi, ii, j, jj, jjinc, k, nvtxs, ncon, cnvtxs, maxidx, + last_unmatched, avgdegree, bnum; idx_t *xadj, *vwgt, *adjncy, *adjwgt, *maxvwgt; - idx_t *match, *cmap, *perm; + idx_t *match, *cmap, *degrees, *perm, *tperm; size_t nunmatched=0; WCOREPUSH; @@ -167,11 +172,24 @@ idx_t Match_RM(ctrl_t *ctrl, graph_t *graph) maxvwgt = ctrl->maxvwgt; - match = iset(nvtxs, UNMATCHED, iwspacemalloc(ctrl, nvtxs)); - perm = iwspacemalloc(ctrl, nvtxs); + match = iset(nvtxs, UNMATCHED, iwspacemalloc(ctrl, nvtxs)); + perm = iwspacemalloc(ctrl, nvtxs); + tperm = iwspacemalloc(ctrl, nvtxs); + degrees = iwspacemalloc(ctrl, nvtxs); - irandArrayPermute(nvtxs, perm, nvtxs/8, 1); + /* Determine a "random" traversal order that is biased towards + low-degree vertices */ + irandArrayPermute(nvtxs, tperm, nvtxs/8, 1); + avgdegree = 4.0*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) { + bnum = sqrt(1+xadj[i+1]-xadj[i]); + degrees[i] = (bnum > avgdegree ? avgdegree : bnum); + } + BucketSortKeysInc(ctrl, nvtxs, avgdegree, degrees, tperm, perm); + + + /* Traverse the vertices and compute the matching */ for (cnvtxs=0, last_unmatched=0, pi=0; pi<nvtxs; pi++) { i = perm[pi]; @@ -204,7 +222,7 @@ idx_t Match_RM(ctrl_t *ctrl, graph_t *graph) } /* If it did not match, record for a 2-hop matching. */ - if (maxidx == i && 3*vwgt[i] < maxvwgt[0]) { + if (maxidx == i && 2*vwgt[i] < maxvwgt[0]) { nunmatched++; maxidx = UNMATCHED; } @@ -276,7 +294,7 @@ idx_t Match_RM(ctrl_t *ctrl, graph_t *graph) idx_t Match_SHEM(ctrl_t *ctrl, graph_t *graph) { idx_t i, pi, ii, j, jj, jjinc, k, nvtxs, ncon, cnvtxs, maxidx, maxwgt, - last_unmatched, avgdegree; + last_unmatched, avgdegree, bnum; idx_t *xadj, *vwgt, *adjncy, *adjwgt, *maxvwgt; idx_t *match, *cmap, *degrees, *perm, *tperm; size_t nunmatched=0; @@ -300,13 +318,18 @@ idx_t Match_SHEM(ctrl_t *ctrl, graph_t *graph) tperm = iwspacemalloc(ctrl, nvtxs); degrees = iwspacemalloc(ctrl, nvtxs); + /* Determine a "random" traversal order that is biased towards low-degree vertices */ irandArrayPermute(nvtxs, tperm, nvtxs/8, 1); - avgdegree = 0.7*(xadj[nvtxs]/nvtxs); - for (i=0; i<nvtxs; i++) - degrees[i] = (xadj[i+1]-xadj[i] > avgdegree ? avgdegree : xadj[i+1]-xadj[i]); + avgdegree = 4.0*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) { + bnum = sqrt(1+xadj[i+1]-xadj[i]); + degrees[i] = (bnum > avgdegree ? avgdegree : bnum); + } BucketSortKeysInc(ctrl, nvtxs, avgdegree, degrees, tperm, perm); + + /* Traverse the vertices and compute the matching */ for (cnvtxs=0, last_unmatched=0, pi=0; pi<nvtxs; pi++) { i = perm[pi]; @@ -341,7 +364,7 @@ idx_t Match_SHEM(ctrl_t *ctrl, graph_t *graph) } /* If it did not match, record for a 2-hop matching. */ - if (maxidx == i && 3*vwgt[i] < maxvwgt[0]) { + if (maxidx == i && 2*vwgt[i] < maxvwgt[0]) { nunmatched++; maxidx = UNMATCHED; } @@ -451,7 +474,7 @@ idx_t Match_2HopAny(ctrl_t *ctrl, graph_t *graph, idx_t *perm, idx_t *match, nunmatched = *r_nunmatched; - /*IFSET(ctrl->dbglvl, METIS_DBG_COARSEN, printf("IN: nunmatched: %zu\t", * nunmatched)); */ + /*IFSET(ctrl->dbglvl, METIS_DBG_COARSEN, printf("IN: nunmatched: %zu\t", nunmatched)); */ /* create the inverted index */ WCOREPUSH; @@ -496,7 +519,7 @@ idx_t Match_2HopAny(ctrl_t *ctrl, graph_t *graph, idx_t *perm, idx_t *match, } WCOREPOP; - /* IFSET(ctrl->dbglvl, METIS_DBG_COARSEN, printf("OUT: nunmatched: %zu\n", nunmatched)); */ + /*IFSET(ctrl->dbglvl, METIS_DBG_COARSEN, printf("OUT: nunmatched: %zu\n", nunmatched)); */ IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->Aux3Tmr)); @@ -594,6 +617,190 @@ idx_t Match_2HopAll(ctrl_t *ctrl, graph_t *graph, idx_t *perm, idx_t *match, } +/*************************************************************************/ +/*! This function finds a matching by selecting an adjacent vertex based + on the Jaccard coefficient of the adjaceny lists. + */ +/**************************************************************************/ +idx_t Match_JC(ctrl_t *ctrl, graph_t *graph) +{ + idx_t i, pi, ii, iii, j, jj, jjj, jjinc, k, nvtxs, ncon, cnvtxs, maxidx, + last_unmatched, avgdegree, bnum; + idx_t *xadj, *vwgt, *adjncy, *adjwgt, *maxvwgt; + idx_t *match, *cmap, *degrees, *perm, *tperm, *vec, *marker; + idx_t mytwgt, xtwgt, ctwgt; + float bscore, score; + + WCOREPUSH; + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->MatchTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + cmap = graph->cmap; + + maxvwgt = ctrl->maxvwgt; + + match = iset(nvtxs, UNMATCHED, iwspacemalloc(ctrl, nvtxs)); + perm = iwspacemalloc(ctrl, nvtxs); + tperm = iwspacemalloc(ctrl, nvtxs); + degrees = iwspacemalloc(ctrl, nvtxs); + + irandArrayPermute(nvtxs, tperm, nvtxs/8, 1); + + avgdegree = 4.0*(xadj[nvtxs]/nvtxs); + for (i=0; i<nvtxs; i++) { + bnum = sqrt(1+xadj[i+1]-xadj[i]); + degrees[i] = (bnum > avgdegree ? avgdegree : bnum); + } + BucketSortKeysInc(ctrl, nvtxs, avgdegree, degrees, tperm, perm); + + /* point to the wspace vectors that are not needed any more */ + vec = tperm; + marker = degrees; + iset(nvtxs, -1, vec); + iset(nvtxs, -1, marker); + + for (cnvtxs=0, last_unmatched=0, pi=0; pi<nvtxs; pi++) { + i = perm[pi]; + + if (match[i] == UNMATCHED) { /* Unmatched */ + maxidx = i; + + if ((ncon == 1 ? vwgt[i] < maxvwgt[0] : ivecle(ncon, vwgt+i*ncon, maxvwgt))) { + /* Deal with island vertices. Find a non-island and match it with. + The matching ignores ctrl->maxvwgt requirements */ + if (xadj[i] == xadj[i+1]) { + last_unmatched = gk_max(pi, last_unmatched)+1; + for (; last_unmatched<nvtxs; last_unmatched++) { + j = perm[last_unmatched]; + if (match[j] == UNMATCHED) { + maxidx = j; + break; + } + } + } + else { + if (ncon == 1) { + /* Find a max JC pair, subject to maxvwgt constraints */ + if (xadj[i+1]-xadj[i] < avgdegree) { + marker[i] = i; + bscore = 0.0; + mytwgt = 0; + for (j=xadj[i]; j<xadj[i+1]; j++) { + mytwgt += 1;//adjwgt[j]; + vec[adjncy[j]] = 1;//adjwgt[j]; + } + + /* single constraint pairing */ +#ifdef XXX + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + if (marker[ii] == i || match[ii] != UNMATCHED || vwgt[i]+vwgt[ii] > maxvwgt[0]) + continue; + + ctwgt = xtwgt = 0; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + xtwgt += adjwgt[jj]; + if (vec[adjncy[jj]] > 0) + ctwgt += vec[adjncy[jj]] + adjwgt[jj]; + else if (adjncy[jj] == i) { + ctwgt += adjwgt[jj]; + xtwgt -= adjwgt[jj]; + } + } + + score = 1.0*ctwgt/(mytwgt+xtwgt-ctwgt); + if (score > bscore) { + bscore = score; + maxidx = ii; + } + marker[ii] = i; + } +#endif + + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + for (jj=xadj[ii]; jj<xadj[ii+1]; jj++) { + iii = adjncy[jj]; + + if (marker[iii] == i || match[iii] != UNMATCHED || vwgt[i]+vwgt[iii] > maxvwgt[0]) + continue; + + ctwgt = xtwgt = 0; + for (jjj=xadj[iii]; jjj<xadj[iii+1]; jjj++) { + xtwgt += 1;//adjwgt[jjj]; + if (vec[adjncy[jjj]] > 0) + ctwgt += 2;//vec[adjncy[jjj]] + adjwgt[jjj]; + else if (adjncy[jjj] == i) + ctwgt += 10*adjwgt[jjj]; + } + + score = 1.0*ctwgt/(mytwgt+xtwgt); + //printf("%"PRIDX" %"PRIDX" %"PRIDX" %.4f\n", mytwgt, xtwgt, ctwgt, score); + if (score > bscore) { + bscore = score; + maxidx = iii; + } + marker[iii] = i; + } + } + + /* reset vec array */ + for (j=xadj[i]; j<xadj[i+1]; j++) + vec[adjncy[j]] = -1; + } + } + else { + /* multi-constraint version */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (match[k] == UNMATCHED && + ivecaxpylez(ncon, 1, vwgt+i*ncon, vwgt+k*ncon, maxvwgt)) { + maxidx = k; + break; + } + } + } + } + } + + if (maxidx != UNMATCHED) { + cmap[i] = cmap[maxidx] = cnvtxs++; + match[i] = maxidx; + match[maxidx] = i; + } + } + } + + + /* match the final unmatched vertices with themselves and reorder the vertices + of the coarse graph for memory-friendly contraction */ + for (cnvtxs=0, i=0; i<nvtxs; i++) { + if (match[i] == UNMATCHED) { + match[i] = i; + cmap[i] = cnvtxs++; + } + else { + if (i <= match[i]) + cmap[i] = cmap[match[i]] = cnvtxs++; + } + } + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->MatchTmr)); + + CreateCoarseGraph(ctrl, graph, cnvtxs, match); + + WCOREPOP; + + return cnvtxs; +} + + /*************************************************************************/ /*! This function prints various stats for each graph during coarsening */ @@ -618,17 +825,20 @@ void PrintCGraphStats(ctrl_t *ctrl, graph_t *graph) linear scan. */ /*************************************************************************/ -void CreateCoarseGraph(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, +void CreateCoarseGraph0(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, idx_t *match) { - idx_t j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, - v, u, mask, dovsize; + idx_t j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u; idx_t *xadj, *vwgt, *vsize, *adjncy, *adjwgt; idx_t *cmap, *htable; idx_t *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt; graph_t *cgraph; + int mask, dovsize, dropedges; + idx_t cv, nkeep, droppedewgt; + idx_t *keys=NULL, *medianewgts=NULL, *noise=NULL; - dovsize = (ctrl->objtype == METIS_OBJTYPE_VOL ? 1 : 0); + dovsize = (ctrl->objtype == METIS_OBJTYPE_VOL ? 1 : 0); + dropedges = ctrl->dropedges; /* Check if the mask-version of the code is a good choice */ mask = HTLENGTH; @@ -658,6 +868,19 @@ void CreateCoarseGraph(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, adjwgt = graph->adjwgt; cmap = graph->cmap; + /* Setup structures for dropedges */ + if (dropedges) { + for (nkeep=-1, v=0; v<nvtxs; v++) + nkeep = gk_max(nkeep, xadj[v+1]-xadj[v]); + + medianewgts = iwspacemalloc(ctrl, cnvtxs); + noise = iwspacemalloc(ctrl, cnvtxs); + keys = iwspacemalloc(ctrl, 2*(nkeep+1)); + + for (v=0; v<cnvtxs; v++) + noise[v] = irandInRange(128); + } + /* Initialize the coarser graph */ cgraph = SetupCoarseGraph(graph, cnvtxs, dovsize); cxadj = cgraph->xadj; @@ -769,10 +992,570 @@ void CreateCoarseGraph(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, htable[cadjncy[j]&mask] = -1; htable[cnvtxs&mask] = -1; + /* Determine the median weight of the incident edges, which will be used + to keep an edge (u, v) iff wgt(u, v) >= min(medianewgts[u], medianewgts[v]) */ + if (dropedges) { + for (j=0; j<nedges; j++) + keys[j] = (cadjwgt[j]<<8) + noise[cnvtxs] + noise[cadjncy[j]]; + isortd(nedges, keys); + medianewgts[cnvtxs] = keys[((xadj[v+1]-xadj[v] + xadj[u+1]-xadj[u])>>1)]; + } + + cadjncy += nedges; + cadjwgt += nedges; + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + } + + /* compact the adjacency structure of the coarser graph to keep only +ve edges */ + if (dropedges) { + droppedewgt = 0; + + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + cnedges = 0; + for (u=0; u<cnvtxs; u++) { + istart = cxadj[u]; + iend = cxadj[u+1]; + for (j=istart; j<iend; j++) { + v = cadjncy[j]; + if ((cadjwgt[j]<<8) + noise[u] + noise[v] >= gk_min(medianewgts[u], medianewgts[v])) { + cadjncy[cnedges] = cadjncy[j]; + cadjwgt[cnedges++] = cadjwgt[j]; + } + else + droppedewgt += cadjwgt[j]; + } + cxadj[u] = cnedges; + } + SHIFTCSR(j, cnvtxs, cxadj); + + //printf("droppedewgt: %d\n", (int)droppedewgt); + + cgraph->droppedewgt = droppedewgt; + } + + cgraph->nedges = cnedges; + + for (j=0; j<ncon; j++) { + cgraph->tvwgt[j] = isum(cgraph->nvtxs, cgraph->vwgt+j, ncon); + cgraph->invtvwgt[j] = 1.0/(cgraph->tvwgt[j] > 0 ? cgraph->tvwgt[j] : 1); + } + + + ReAdjustMemory(ctrl, graph, cgraph); + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ContractTmr)); + + WCOREPOP; +} + + +/*************************************************************************/ +/*! This function creates the coarser graph. It uses a simple hash-table + for identifying the adjacent vertices that get collapsed to the same + node. The hash-table can have conflicts, which are handled via a + linear scan. + */ +/*************************************************************************/ +void CreateCoarseGraph1(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, + idx_t *match) +{ + idx_t j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, + cnedges, v, u, mask; + idx_t *xadj, *vwgt, *vsize, *adjncy, *adjwgt; + idx_t *cmap, *htable, *table; + idx_t *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt; + graph_t *cgraph; + int dovsize, dropedges, usemask; + idx_t cv, nkeep, droppedewgt; + idx_t *keys=NULL, *medianewgts=NULL, *noise=NULL; + + WCOREPUSH; + + dovsize = (ctrl->objtype == METIS_OBJTYPE_VOL ? 1 : 0); + dropedges = ctrl->dropedges; + + mask = HTLENGTH; + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + cmap = graph->cmap; + + /* Setup structures for dropedges */ + if (dropedges) { + for (nkeep=-1, v=0; v<nvtxs; v++) + nkeep = gk_max(nkeep, xadj[v+1]-xadj[v]); + + medianewgts = iwspacemalloc(ctrl, cnvtxs); + noise = iwspacemalloc(ctrl, cnvtxs); + keys = iwspacemalloc(ctrl, 2*(nkeep+1)); + + for (v=0; v<cnvtxs; v++) + noise[v] = irandInRange(128); + } + + /* Initialize the coarser graph */ + cgraph = SetupCoarseGraph(graph, cnvtxs, dovsize); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cvsize = cgraph->vsize; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + htable = iset(gk_min(cnvtxs+1, mask+1), -1, iwspacemalloc(ctrl, mask+1)); + table = iset(cnvtxs, -1, iwspacemalloc(ctrl, cnvtxs)); + + cxadj[0] = cnvtxs = cnedges = 0; + for (v=0; v<nvtxs; v++) { + if ((u = match[v]) < v) + continue; + + ASSERT(cmap[v] == cnvtxs); + ASSERT(cmap[match[v]] == cnvtxs); + + /* take care of the vertices */ + if (ncon == 1) + cvwgt[cnvtxs] = vwgt[v]; + else + icopy(ncon, vwgt+v*ncon, cvwgt+cnvtxs*ncon); + + if (dovsize) + cvsize[cnvtxs] = vsize[v]; + + if (v != u) { + if (ncon == 1) + cvwgt[cnvtxs] += vwgt[u]; + else + iaxpy(ncon, 1, vwgt+u*ncon, 1, cvwgt+cnvtxs*ncon, 1); + + if (dovsize) + cvsize[cnvtxs] += vsize[u]; + } + + + /* take care of the edges */ + usemask = ((xadj[v+1]-xadj[v] + xadj[u+1]-xadj[u]) > (mask>>3) ? 0 : 1); + nedges = 0; + + + if (usemask) { + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m] += adjwgt[j]; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj] += adjwgt[j]; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = adjwgt[j]; + } + } + } + + if (v != u) { + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + kk = k&mask; + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else if (cadjncy[m] == k) { + cadjwgt[m] += adjwgt[j]; + } + else { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == k) { + cadjwgt[jj] += adjwgt[j]; + break; + } + } + if (jj == nedges) { + cadjncy[nedges] = k; + cadjwgt[nedges++] = adjwgt[j]; + } + } + } + + /* Remove the contracted adjacency weight */ + jj = htable[cnvtxs&mask]; + if (jj >= 0 && cadjncy[jj] != cnvtxs) { + for (jj=0; jj<nedges; jj++) { + if (cadjncy[jj] == cnvtxs) + break; + } + } + /* This 2nd check is needed for non-adjacent matchings */ + if (jj >= 0 && jj < nedges && cadjncy[jj] == cnvtxs) { + cadjncy[jj] = cadjncy[--nedges]; + cadjwgt[jj] = cadjwgt[nedges]; + } + } + + /* Zero out the htable */ + for (j=0; j<nedges; j++) + htable[cadjncy[j]&mask] = -1; + htable[cnvtxs&mask] = -1; + } + else { + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if ((m = table[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + table[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + if (v != u) { + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if ((m = table[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + table[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + /* Remove the contracted adjacency weight */ + if ((j = table[cnvtxs]) != -1) { + ASSERT(cadjncy[j] == cnvtxs); + cadjncy[j] = cadjncy[--nedges]; + cadjwgt[j] = cadjwgt[nedges]; + table[cnvtxs] = -1; + } + } + + /* Zero out the htable */ + for (j=0; j<nedges; j++) + table[cadjncy[j]] = -1; + } + + + /* Determine the median weight of the incident edges, which will be used + to keep an edge (u, v) iff wgt(u, v) >= min(medianewgts[u], medianewgts[v]) */ + if (dropedges) { + for (j=0; j<nedges; j++) + keys[j] = (cadjwgt[j]<<8) + noise[cnvtxs] + noise[cadjncy[j]]; + isortd(nedges, keys); + medianewgts[cnvtxs] = keys[((xadj[v+1]-xadj[v] + xadj[u+1]-xadj[u])>>1)]; + } + + cadjncy += nedges; + cadjwgt += nedges; cnedges += nedges; cxadj[++cnvtxs] = cnedges; + } + + /* compact the adjacency structure of the coarser graph to keep only +ve edges */ + if (dropedges) { + droppedewgt = 0; + + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + cnedges = 0; + for (u=0; u<cnvtxs; u++) { + istart = cxadj[u]; + iend = cxadj[u+1]; + for (j=istart; j<iend; j++) { + v = cadjncy[j]; + if ((cadjwgt[j]<<8) + noise[u] + noise[v] >= gk_min(medianewgts[u], medianewgts[v])) { + cadjncy[cnedges] = cadjncy[j]; + cadjwgt[cnedges++] = cadjwgt[j]; + } + else + droppedewgt += cadjwgt[j]; + } + cxadj[u] = cnedges; + } + SHIFTCSR(j, cnvtxs, cxadj); + + //printf("droppedewgt: %d\n", (int)droppedewgt); + + cgraph->droppedewgt = droppedewgt; + } + + cgraph->nedges = cnedges; + + for (j=0; j<ncon; j++) { + cgraph->tvwgt[j] = isum(cgraph->nvtxs, cgraph->vwgt+j, ncon); + cgraph->invtvwgt[j] = 1.0/(cgraph->tvwgt[j] > 0 ? cgraph->tvwgt[j] : 1); + } + + + ReAdjustMemory(ctrl, graph, cgraph); + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ContractTmr)); + + WCOREPOP; +} + + +/*************************************************************************/ +/*! This function creates the coarser graph. Depending on the size of the + candidate adjancency lists it either uses a hash table or an array + to do duplicate detection. + */ +/*************************************************************************/ +void CreateCoarseGraph(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, + idx_t *match) +{ + idx_t j, jj, k, kk, l, m, istart, iend, nvtxs, nedges, ncon, + cnedges, v, u, mask; + idx_t *xadj, *vwgt, *vsize, *adjncy, *adjwgt; + idx_t *cmap, *htable, *table; + idx_t *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt; + graph_t *cgraph; + int dovsize, dropedges; + idx_t cv, nkeep, droppedewgt; + idx_t *keys=NULL, *medianewgts=NULL, *noise=NULL; + + WCOREPUSH; + + dovsize = (ctrl->objtype == METIS_OBJTYPE_VOL ? 1 : 0); + dropedges = ctrl->dropedges; + + mask = HTLENGTH; + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ContractTmr)); + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + vwgt = graph->vwgt; + vsize = graph->vsize; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + cmap = graph->cmap; + + /* Setup structures for dropedges */ + if (dropedges) { + for (nkeep=-1, v=0; v<nvtxs; v++) + nkeep = gk_max(nkeep, xadj[v+1]-xadj[v]); + + medianewgts = iwspacemalloc(ctrl, cnvtxs); + noise = iwspacemalloc(ctrl, cnvtxs); + keys = iwspacemalloc(ctrl, 2*(nkeep+1)); + + for (v=0; v<cnvtxs; v++) + noise[v] = irandInRange(128); + } + + /* Initialize the coarser graph */ + cgraph = SetupCoarseGraph(graph, cnvtxs, dovsize); + cxadj = cgraph->xadj; + cvwgt = cgraph->vwgt; + cvsize = cgraph->vsize; + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + htable = iset(gk_min(cnvtxs+1, mask+1), -1, iwspacemalloc(ctrl, mask+1)); + table = iset(cnvtxs, -1, iwspacemalloc(ctrl, cnvtxs)); + + cxadj[0] = cnvtxs = cnedges = 0; + for (v=0; v<nvtxs; v++) { + if ((u = match[v]) < v) + continue; + + ASSERT(cmap[v] == cnvtxs); + ASSERT(cmap[match[v]] == cnvtxs); + + /* take care of the vertices */ + if (ncon == 1) + cvwgt[cnvtxs] = vwgt[v]; + else + icopy(ncon, vwgt+v*ncon, cvwgt+cnvtxs*ncon); + + if (dovsize) + cvsize[cnvtxs] = vsize[v]; + + if (v != u) { + if (ncon == 1) + cvwgt[cnvtxs] += vwgt[u]; + else + iaxpy(ncon, 1, vwgt+u*ncon, 1, cvwgt+cnvtxs*ncon, 1); + + if (dovsize) + cvsize[cnvtxs] += vsize[u]; + } + + + /* take care of the edges */ + if ((xadj[v+1]-xadj[v] + xadj[u+1]-xadj[u]) < (mask>>2)) { /* use mask */ + /* put the ID of the contracted node itself at the start, so that it can be + * removed easily */ + htable[cnvtxs&mask] = 0; + cadjncy[0] = cnvtxs; + nedges = 1; + + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + for (kk=k&mask; htable[kk]!=-1 && cadjncy[htable[kk]]!=k; kk=((kk+1)%mask)); + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + if (v != u) { + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + for (kk=k&mask; htable[kk]!=-1 && cadjncy[htable[kk]]!=k; kk=((kk+1)%mask)); + if ((m = htable[kk]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + htable[kk] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + } + + /* zero out the htable */ + for (j=0; j<nedges; j++) { + k = cadjncy[j]; + for (kk=k&mask; cadjncy[htable[kk]]!=k; kk=((kk+1)%mask)); + htable[kk] = -1; + } + + /* remove the contracted vertex from the list */ + cadjncy[0] = cadjncy[--nedges]; + cadjwgt[0] = cadjwgt[nedges]; + } + else { + nedges = 0; + istart = xadj[v]; + iend = xadj[v+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if ((m = table[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + table[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + if (v != u) { + istart = xadj[u]; + iend = xadj[u+1]; + for (j=istart; j<iend; j++) { + k = cmap[adjncy[j]]; + if ((m = table[k]) == -1) { + cadjncy[nedges] = k; + cadjwgt[nedges] = adjwgt[j]; + table[k] = nedges++; + } + else { + cadjwgt[m] += adjwgt[j]; + } + } + + /* Remove the contracted adjacency weight */ + if ((j = table[cnvtxs]) != -1) { + ASSERT(cadjncy[j] == cnvtxs); + cadjncy[j] = cadjncy[--nedges]; + cadjwgt[j] = cadjwgt[nedges]; + table[cnvtxs] = -1; + } + } + + /* Zero out the htable */ + for (j=0; j<nedges; j++) + table[cadjncy[j]] = -1; + } + + + /* Determine the median weight of the incident edges, which will be used + to keep an edge (u, v) iff wgt(u, v) >= min(medianewgts[u], medianewgts[v]) */ + if (dropedges) { + for (j=0; j<nedges; j++) + keys[j] = (cadjwgt[j]<<8) + noise[cnvtxs] + noise[cadjncy[j]]; + isortd(nedges, keys); + medianewgts[cnvtxs] = keys[((xadj[v+1]-xadj[v] + xadj[u+1]-xadj[u])>>1)]; + } + cadjncy += nedges; cadjwgt += nedges; + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + } + + /* compact the adjacency structure of the coarser graph to keep only +ve edges */ + if (dropedges) { + droppedewgt = 0; + + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + cnedges = 0; + for (u=0; u<cnvtxs; u++) { + istart = cxadj[u]; + iend = cxadj[u+1]; + for (j=istart; j<iend; j++) { + v = cadjncy[j]; + if ((cadjwgt[j]<<8) + noise[u] + noise[v] >= gk_min(medianewgts[u], medianewgts[v])) { + cadjncy[cnedges] = cadjncy[j]; + cadjwgt[cnedges++] = cadjwgt[j]; + } + else + droppedewgt += cadjwgt[j]; + } + cxadj[u] = cnedges; + } + SHIFTCSR(j, cnvtxs, cxadj); + + //printf("droppedewgt: %d\n", (int)droppedewgt); + + cgraph->droppedewgt = droppedewgt; } cgraph->nedges = cnedges; @@ -800,15 +1583,19 @@ void CreateCoarseGraph(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, void CreateCoarseGraphNoMask(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, idx_t *match) { - idx_t j, k, m, istart, iend, nvtxs, nedges, ncon, cnedges, v, u, dovsize; + idx_t j, k, m, istart, iend, v, u, nvtxs, nedges, ncon, cnedges; idx_t *xadj, *vwgt, *vsize, *adjncy, *adjwgt; idx_t *cmap, *htable; idx_t *cxadj, *cvwgt, *cvsize, *cadjncy, *cadjwgt; graph_t *cgraph; + int dovsize, dropedges; + idx_t cv, nkeep, droppedewgt; + idx_t *keys=NULL, *medianewgts=NULL, *noise=NULL; WCOREPUSH; - dovsize = (ctrl->objtype == METIS_OBJTYPE_VOL ? 1 : 0); + dovsize = (ctrl->objtype == METIS_OBJTYPE_VOL ? 1 : 0); + dropedges = ctrl->dropedges; IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ContractTmr)); @@ -821,6 +1608,18 @@ void CreateCoarseGraphNoMask(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, adjwgt = graph->adjwgt; cmap = graph->cmap; + /* Setup structures for dropedges */ + if (dropedges) { + for (nkeep=-1, v=0; v<nvtxs; v++) + nkeep = gk_max(nkeep, xadj[v+1]-xadj[v]); + + medianewgts = iwspacemalloc(ctrl, cnvtxs); + noise = iwspacemalloc(ctrl, cnvtxs); + keys = iwspacemalloc(ctrl, 2*(nkeep+1)); + + for (v=0; v<cnvtxs; v++) + noise[v] = irandInRange(128); + } /* Initialize the coarser graph */ cgraph = SetupCoarseGraph(graph, cnvtxs, dovsize); @@ -900,10 +1699,51 @@ void CreateCoarseGraphNoMask(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, for (j=0; j<nedges; j++) htable[cadjncy[j]] = -1; - cnedges += nedges; - cxadj[++cnvtxs] = cnedges; + + /* Determine the median weight of the incident edges, which will be used + to keep an edge (u, v) iff wgt(u, v) >= min(medianewgts[u], medianewgts[v]) */ + if (dropedges) { + for (j=0; j<nedges; j++) + keys[j] = (cadjwgt[j]<<8) + noise[cnvtxs] + noise[cadjncy[j]]; + isortd(nedges, keys); + medianewgts[cnvtxs] = keys[((xadj[v+1]-xadj[v] + xadj[u+1]-xadj[u])>>1)]; + } + + /* Record Advance the cadjXXX pointers */ cadjncy += nedges; cadjwgt += nedges; + cnedges += nedges; + cxadj[++cnvtxs] = cnedges; + } + + + /* compact the adjacency structure of the coarser graph to keep only +ve edges */ + if (dropedges) { + droppedewgt = 0; + + cadjncy = cgraph->adjncy; + cadjwgt = cgraph->adjwgt; + + cnedges = 0; + for (u=0; u<cnvtxs; u++) { + istart = cxadj[u]; + iend = cxadj[u+1]; + for (j=istart; j<iend; j++) { + v = cadjncy[j]; + if ((cadjwgt[j]<<8) + noise[u] + noise[v] >= gk_min(medianewgts[u], medianewgts[v])) { + cadjncy[cnedges] = cadjncy[j]; + cadjwgt[cnedges++] = cadjwgt[j]; + } + else + droppedewgt += cadjwgt[j]; + } + cxadj[u] = cnedges; + } + SHIFTCSR(j, cnvtxs, cxadj); + + //printf("droppedewgt: %d\n", (int)droppedewgt); + + cgraph->droppedewgt = droppedewgt; } cgraph->nedges = cnedges; @@ -1090,7 +1930,7 @@ void CreateCoarseGraphPerm(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, /*! Setup the various arrays for the coarse graph */ /*************************************************************************/ -graph_t *SetupCoarseGraph(graph_t *graph, idx_t cnvtxs, idx_t dovsize) +graph_t *SetupCoarseGraph(graph_t *graph, idx_t cnvtxs, int dovsize) { graph_t *cgraph; @@ -1102,7 +1942,6 @@ graph_t *SetupCoarseGraph(graph_t *graph, idx_t cnvtxs, idx_t dovsize) cgraph->finer = graph; graph->coarser = cgraph; - /* Allocate memory for the coarser graph */ cgraph->xadj = imalloc(cnvtxs+1, "SetupCoarseGraph: xadj"); cgraph->adjncy = imalloc(graph->nedges, "SetupCoarseGraph: adjncy"); diff --git a/3rdParty/metis/metis-5.1.0/libmetis/compress.c b/3rdParty/metis/metis-5.1.1/libmetis/compress.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/compress.c rename to 3rdParty/metis/metis-5.1.1/libmetis/compress.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/contig.c b/3rdParty/metis/metis-5.1.1/libmetis/contig.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/contig.c rename to 3rdParty/metis/metis-5.1.1/libmetis/contig.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/debug.c b/3rdParty/metis/metis-5.1.1/libmetis/debug.c similarity index 98% rename from 3rdParty/metis/metis-5.1.0/libmetis/debug.c rename to 3rdParty/metis/metis-5.1.1/libmetis/debug.c index e188135da57ca7b4ccbebcffb6deaee33ad971a9..47aba6165a06c60b9b3d8ffa6b0ce95c444fa6d1 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/debug.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/debug.c @@ -56,7 +56,7 @@ idx_t ComputeVolume(graph_t *graph, idx_t *where) adjncy = graph->adjncy; vsize = graph->vsize; - nparts = where[iargmax(nvtxs, where)]+1; + nparts = where[iargmax(nvtxs, where,1)]+1; marker = ismalloc(nparts, -1, "ComputeVolume: marker"); totalv = 0; @@ -104,9 +104,9 @@ idx_t ComputeMaxCut(graph_t *graph, idx_t nparts, idx_t *where) } } - maxcut = cuts[iargmax(nparts, cuts)]; + maxcut = cuts[iargmax(nparts, cuts,1)]; - printf("%zu => %"PRIDX"\n", iargmax(nparts, cuts), maxcut); + printf("%zu => %"PRIDX"\n", iargmax(nparts, cuts,1), maxcut); gk_free((void **)&cuts, LTERM); diff --git a/3rdParty/metis/metis-5.1.0/libmetis/defs.h b/3rdParty/metis/metis-5.1.1/libmetis/defs.h similarity index 92% rename from 3rdParty/metis/metis-5.1.0/libmetis/defs.h rename to 3rdParty/metis/metis-5.1.1/libmetis/defs.h index 1961178388a96af3bd01792d155c478afbe82c23..7d837e26528249967e05d64218f5bd4eeb847ed6 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/defs.h +++ b/3rdParty/metis/metis-5.1.1/libmetis/defs.h @@ -8,19 +8,19 @@ * Started 8/27/94 * George * - * $Id: defs.h 13933 2013-03-29 22:20:46Z karypis $ + * $Id: defs.h 20398 2016-11-22 17:17:12Z karypis $ * */ #ifndef _LIBMETIS_DEFS_H_ #define _LIBMETIS_DEFS_H_ -#define METISTITLE "METIS 5.0 Copyright 1998-13, Regents of the University of Minnesota\n" +#define METISTITLE "METIS 5.2 Copyright 1998-16, Regents of the University of Minnesota\n" #define MAXLINE 1280000 #define LTERM (void **) 0 /* List terminator for gk_free() */ -#define HTLENGTH ((1<<11)-1) +#define HTLENGTH ((1<<13)-1) #define INIT_MAXNAD 200 /* Initial number of maximum number of adjacent domains. This number will be diff --git a/3rdParty/metis/metis-5.1.0/libmetis/fm.c b/3rdParty/metis/metis-5.1.1/libmetis/fm.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/fm.c rename to 3rdParty/metis/metis-5.1.1/libmetis/fm.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/fortran.c b/3rdParty/metis/metis-5.1.1/libmetis/fortran.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/fortran.c rename to 3rdParty/metis/metis-5.1.1/libmetis/fortran.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/frename.c b/3rdParty/metis/metis-5.1.1/libmetis/frename.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/frename.c rename to 3rdParty/metis/metis-5.1.1/libmetis/frename.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/gklib.c b/3rdParty/metis/metis-5.1.1/libmetis/gklib.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/gklib.c rename to 3rdParty/metis/metis-5.1.1/libmetis/gklib.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/gklib_defs.h b/3rdParty/metis/metis-5.1.1/libmetis/gklib_defs.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/gklib_defs.h rename to 3rdParty/metis/metis-5.1.1/libmetis/gklib_defs.h diff --git a/3rdParty/metis/metis-5.1.0/libmetis/gklib_rename.h b/3rdParty/metis/metis-5.1.1/libmetis/gklib_rename.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/gklib_rename.h rename to 3rdParty/metis/metis-5.1.1/libmetis/gklib_rename.h diff --git a/3rdParty/metis/metis-5.1.0/libmetis/graph.c b/3rdParty/metis/metis-5.1.1/libmetis/graph.c similarity index 65% rename from 3rdParty/metis/metis-5.1.0/libmetis/graph.c rename to 3rdParty/metis/metis-5.1.1/libmetis/graph.c index 37f7d09dc83bc9377ccb0369d90e3ed33f9f732c..5a24276498741d88e82c7c1b4d42c51e497d8019 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/graph.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/graph.c @@ -5,7 +5,7 @@ \date Started 7/25/1997 \author George \author Copyright 1997-2009, Regents of the University of Minnesota -\version\verbatim $Id: graph.c 10513 2011-07-07 22:06:03Z karypis $ \endverbatim +\version\verbatim $Id: graph.c 15817 2013-11-25 14:58:41Z karypis $ \endverbatim */ #include "metislib.h" @@ -34,6 +34,7 @@ graph_t *SetupGraph(ctrl_t *ctrl, idx_t nvtxs, idx_t ncon, idx_t *xadj, graph->adjncy = adjncy; graph->free_adjncy = 0; + graph->droppedewgt = 0; /* setup the vertex weights */ if (vwgt) { @@ -219,6 +220,7 @@ void InitGraph(graph_t *graph) /* linked-list structure */ graph->coarser = NULL; graph->finer = NULL; + } @@ -272,3 +274,150 @@ void FreeGraph(graph_t **r_graph) } +/*************************************************************************/ +/*! This function writes the key contents of the graph on disk and frees + the associated memory */ +/*************************************************************************/ +void graph_WriteToDisk(ctrl_t *ctrl, graph_t *graph) +{ + idx_t nvtxs, ncon, *xadj; + static int gID = 1; + char outfile[1024]; + FILE *fpout; + + if (ctrl->ondisk == 0) + return; + + if (sizeof(idx_t)*(graph->nvtxs*(graph->ncon+1)+2*graph->xadj[graph->nvtxs]) < 128*1024*1024) + return; + + if (graph->gID > 0) { + sprintf(outfile, "metis%d.%d", (int)ctrl->pid, graph->gID); + gk_rmpath(outfile); + } + + graph->gID = gID++; + sprintf(outfile, "metis%d.%d", (int)ctrl->pid, graph->gID); + + if ((fpout = fopen(outfile, "wb")) == NULL) + return; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + xadj = graph->xadj; + + if (graph->free_xadj) { + if (fwrite(graph->xadj, sizeof(idx_t), nvtxs+1, fpout) != nvtxs+1) + goto error; + } + if (graph->free_vwgt) { + if (fwrite(graph->vwgt, sizeof(idx_t), nvtxs*ncon, fpout) != nvtxs*ncon) + goto error; + } + if (graph->free_adjncy) { + if (fwrite(graph->adjncy, sizeof(idx_t), xadj[nvtxs], fpout) != xadj[nvtxs]) + goto error; + } + if (graph->free_adjwgt) { + if (fwrite(graph->adjwgt, sizeof(idx_t), xadj[nvtxs], fpout) != xadj[nvtxs]) + goto error; + } + if (ctrl->objtype == METIS_OBJTYPE_VOL) { + if (graph->free_vsize) { + if (fwrite(graph->vsize, sizeof(idx_t), nvtxs, fpout) != nvtxs) + goto error; + } + } + + fclose(fpout); + + if (graph->free_xadj) + gk_free((void **)&graph->xadj, LTERM); + if (graph->free_vwgt) + gk_free((void **)&graph->vwgt, LTERM); + if (graph->free_vsize) + gk_free((void **)&graph->vsize, LTERM); + if (graph->free_adjncy) + gk_free((void **)&graph->adjncy, LTERM); + if (graph->free_adjwgt) + gk_free((void **)&graph->adjwgt, LTERM); + + graph->ondisk = 1; + return; + +error: + printf("Failed on writing %s\n", outfile); + fclose(fpout); + gk_rmpath(outfile); + graph->ondisk = 0; +} + + +/*************************************************************************/ +/*! This function reads the key contents of a graph from the disk */ +/*************************************************************************/ +void graph_ReadFromDisk(ctrl_t *ctrl, graph_t *graph) +{ + idx_t nvtxs, ncon, *xadj; + char infile[1024]; + FILE *fpin; + + if (graph->ondisk == 0) + return; /* this graph is not on the disk */ + + sprintf(infile, "metis%d.%d", (int)ctrl->pid, graph->gID); + + if ((fpin = fopen(infile, "rb")) == NULL) + return; + + nvtxs = graph->nvtxs; + ncon = graph->ncon; + + if (graph->free_xadj) { + graph->xadj = imalloc(nvtxs+1, "graph_ReadFromDisk: xadj"); + if (fread(graph->xadj, sizeof(idx_t), nvtxs+1, fpin) != nvtxs+1) + goto error; + } + xadj = graph->xadj; + + if (graph->free_vwgt) { + graph->vwgt = imalloc(nvtxs*ncon, "graph_ReadFromDisk: vwgt"); + if (fread(graph->vwgt, sizeof(idx_t), nvtxs*ncon, fpin) != nvtxs*ncon) + goto error; + } + + if (graph->free_adjncy) { + graph->adjncy = imalloc(xadj[nvtxs], "graph_ReadFromDisk: adjncy"); + if (fread(graph->adjncy, sizeof(idx_t), xadj[nvtxs], fpin) != xadj[nvtxs]) + goto error; + } + + if (graph->free_adjwgt) { + graph->adjwgt = imalloc(xadj[nvtxs], "graph_ReadFromDisk: adjwgt"); + if (fread(graph->adjwgt, sizeof(idx_t), xadj[nvtxs], fpin) != xadj[nvtxs]) + goto error; + } + + if (ctrl->objtype == METIS_OBJTYPE_VOL) { + if (graph->free_vsize) { + graph->vsize = imalloc(nvtxs, "graph_ReadFromDisk: vsize"); + if (fread(graph->vsize, sizeof(idx_t), nvtxs, fpin) != nvtxs) + goto error; + } + } + + fclose(fpin); +// printf("ondisk: deleting %s\n", infile); + gk_rmpath(infile); + + graph->gID = 0; + graph->ondisk = 0; + return; + +error: + fclose(fpin); + gk_rmpath(infile); + graph->ondisk = 0; + gk_errexit(SIGERR, "Failed to restore graph %s from the disk.\n", infile); +} + diff --git a/3rdParty/metis/metis-5.1.0/libmetis/initpart.c b/3rdParty/metis/metis-5.1.1/libmetis/initpart.c similarity index 99% rename from 3rdParty/metis/metis-5.1.0/libmetis/initpart.c rename to 3rdParty/metis/metis-5.1.1/libmetis/initpart.c index 2f6c81b7288f83b1857e803af78ebcc8fa4fb7e6..f2fd3c962606845459d59dbfa8ded56e6815b4a7 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/initpart.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/initpart.c @@ -349,7 +349,7 @@ void McRandomBisection(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, /* partition by spliting the queues randomly */ for (ii=0; ii<nvtxs; ii++) { i = perm[ii]; - qnum = iargmax(ncon, vwgt+i*ncon); + qnum = iargmax(ncon, vwgt+i*ncon,1); where[i] = (counts[qnum]++)%2; } diff --git a/3rdParty/metis/metis-5.1.1/libmetis/kmetis.c b/3rdParty/metis/metis-5.1.1/libmetis/kmetis.c new file mode 100644 index 0000000000000000000000000000000000000000..6babf1cbc3674d13a9cfcb0ddd5f53342ed92b8d --- /dev/null +++ b/3rdParty/metis/metis-5.1.1/libmetis/kmetis.c @@ -0,0 +1,619 @@ +/*! +\file +\brief The top-level routines for multilevel k-way partitioning that minimizes + the edge cut. + +\date Started 7/28/1997 +\author George +\author Copyright 1997-2011, Regents of the University of Minnesota +\version\verbatim $Id: kmetis.c 20398 2016-11-22 17:17:12Z karypis $ \endverbatim +*/ + +#include "metislib.h" + + +/*************************************************************************/ +/*! This function is the entry point for MCKMETIS */ +/*************************************************************************/ +int METIS_PartGraphKway(idx_t *nvtxs, idx_t *ncon, idx_t *xadj, idx_t *adjncy, + idx_t *vwgt, idx_t *vsize, idx_t *adjwgt, idx_t *nparts, + real_t *tpwgts, real_t *ubvec, idx_t *options, idx_t *objval, + idx_t *part) +{ + int sigrval=0, renumber=0; + graph_t *graph; + ctrl_t *ctrl; + + /* set up malloc cleaning code and signal catchers */ + if (!gk_malloc_init()) + return METIS_ERROR_MEMORY; + + gk_sigtrap(); + + if ((sigrval = gk_sigcatch()) != 0) + goto SIGTHROW; + + + /* set up the run parameters */ + ctrl = SetupCtrl(METIS_OP_KMETIS, options, *ncon, *nparts, tpwgts, ubvec); + if (!ctrl) { + gk_siguntrap(); + return METIS_ERROR_INPUT; + } + + /* if required, change the numbering to 0 */ + if (ctrl->numflag == 1) { + Change2CNumbering(*nvtxs, xadj, adjncy); + renumber = 1; + } + + /* set up the graph */ + graph = SetupGraph(ctrl, *nvtxs, *ncon, xadj, adjncy, vwgt, vsize, adjwgt); + + /* set up multipliers for making balance computations easier */ + SetupKWayBalMultipliers(ctrl, graph); + + /* set various run parameters that depend on the graph */ + ctrl->CoarsenTo = gk_max((*nvtxs)/(40*gk_log2(*nparts)), 30*(*nparts)); + ctrl->nIparts = (ctrl->nIparts != -1 ? ctrl->nIparts : (ctrl->CoarsenTo == 30*(*nparts) ? 4 : 5)); + + /* take care contiguity requests for disconnected graphs */ + if (ctrl->contig && !IsConnected(graph, 0)) + gk_errexit(SIGERR, "METIS Error: A contiguous partition is requested for a non-contiguous input graph.\n"); + + /* allocate workspace memory */ + AllocateWorkSpace(ctrl, graph); + + /* start the partitioning */ + IFSET(ctrl->dbglvl, METIS_DBG_TIME, InitTimers(ctrl)); + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->TotalTmr)); + + if (ctrl->dbglvl&512) { + *objval = BlockKWayPartitioning(ctrl, graph, part); + } + else { + *objval = MlevelKWayPartitioning(ctrl, graph, part); + } + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->TotalTmr)); + IFSET(ctrl->dbglvl, METIS_DBG_TIME, PrintTimers(ctrl)); + + /* clean up */ + FreeCtrl(&ctrl); + +SIGTHROW: + /* if required, change the numbering back to 1 */ + if (renumber) + Change2FNumbering(*nvtxs, xadj, adjncy, part); + + gk_siguntrap(); + gk_malloc_cleanup(0); + + return metis_rcode(sigrval); +} + + +/*************************************************************************/ +/*! This function computes a k-way partitioning of a graph that minimizes + the specified objective function. + + \param ctrl is the control structure + \param graph is the graph to be partitioned + \param part is the vector that on return will store the partitioning + + \returns the objective value of the partitoning. The partitioning + itself is stored in the part vector. +*/ +/*************************************************************************/ +idx_t MlevelKWayPartitioning(ctrl_t *ctrl, graph_t *graph, idx_t *part) +{ + idx_t i, j, objval=0, curobj=0, bestobj=0; + real_t curbal=0.0, bestbal=0.0; + graph_t *cgraph; + int status; + + + for (i=0; i<ctrl->ncuts; i++) { + cgraph = CoarsenGraph(ctrl, graph); + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->InitPartTmr)); + AllocateKWayPartitionMemory(ctrl, cgraph); + + /* Release the work space */ + FreeWorkSpace(ctrl); + + /* Compute the initial partitioning */ + InitKWayPartitioning(ctrl, cgraph); + + /* Re-allocate the work space */ + AllocateWorkSpace(ctrl, graph); + AllocateRefinementWorkSpace(ctrl, 2*cgraph->nedges); + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->InitPartTmr)); + IFSET(ctrl->dbglvl, METIS_DBG_IPART, + printf("Initial %"PRIDX"-way partitioning cut: %"PRIDX"\n", ctrl->nparts, objval)); + + RefineKWay(ctrl, graph, cgraph); + + switch (ctrl->objtype) { + case METIS_OBJTYPE_CUT: + curobj = graph->mincut; + break; + + case METIS_OBJTYPE_VOL: + curobj = graph->minvol; + break; + + default: + gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype); + } + + curbal = ComputeLoadImbalanceDiff(graph, ctrl->nparts, ctrl->pijbm, ctrl->ubfactors); + + if (i == 0 + || (curbal <= 0.0005 && bestobj > curobj) + || (bestbal > 0.0005 && curbal < bestbal)) { + icopy(graph->nvtxs, graph->where, part); + bestobj = curobj; + bestbal = curbal; + } + + FreeRData(graph); + + if (bestobj == 0) + break; + } + + FreeGraph(&graph); + + return bestobj; +} + + +/*************************************************************************/ +/*! This function computes the initial k-way partitioning using PMETIS +*/ +/*************************************************************************/ +void InitKWayPartitioning(ctrl_t *ctrl, graph_t *graph) +{ + idx_t i, ntrials, options[METIS_NOPTIONS], curobj=0, bestobj=0; + idx_t *bestwhere=NULL; + real_t *ubvec=NULL; + int status; + + METIS_SetDefaultOptions(options); + //options[METIS_OPTION_NITER] = 10; + options[METIS_OPTION_NITER] = ctrl->niter; + options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT; + options[METIS_OPTION_NO2HOP] = ctrl->no2hop; + options[METIS_OPTION_ONDISK] = ctrl->ondisk; + options[METIS_OPTION_DROPEDGES] = ctrl->dropedges; + + ubvec = rmalloc(graph->ncon, "InitKWayPartitioning: ubvec"); + for (i=0; i<graph->ncon; i++) + ubvec[i] = (real_t)pow(ctrl->ubfactors[i], 1.0/log(ctrl->nparts)); + + + switch (ctrl->objtype) { + case METIS_OBJTYPE_CUT: + case METIS_OBJTYPE_VOL: + options[METIS_OPTION_NCUTS] = ctrl->nIparts; + status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, + graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, + graph->adjwgt, &ctrl->nparts, ctrl->tpwgts, ubvec, + options, &curobj, graph->where); + + if (status != METIS_OK) + gk_errexit(SIGERR, "Failed during initial partitioning\n"); + + break; + +#ifdef XXX /* This does not seem to help */ + case METIS_OBJTYPE_VOL: + bestwhere = imalloc(graph->nvtxs, "InitKWayPartitioning: bestwhere"); + options[METIS_OPTION_NCUTS] = 2; + + ntrials = (ctrl->nIparts+1)/2; + for (i=0; i<ntrials; i++) { + status = METIS_PartGraphRecursive(&graph->nvtxs, &graph->ncon, + graph->xadj, graph->adjncy, graph->vwgt, graph->vsize, + graph->adjwgt, &ctrl->nparts, ctrl->tpwgts, ubvec, + options, &curobj, graph->where); + if (status != METIS_OK) + gk_errexit(SIGERR, "Failed during initial partitioning\n"); + + curobj = ComputeVolume(graph, graph->where); + + if (i == 0 || bestobj > curobj) { + bestobj = curobj; + if (i < ntrials-1) + icopy(graph->nvtxs, graph->where, bestwhere); + } + + if (bestobj == 0) + break; + } + if (bestobj != curobj) + icopy(graph->nvtxs, bestwhere, graph->where); + + break; +#endif + + default: + gk_errexit(SIGERR, "Unknown objtype: %d\n", ctrl->objtype); + } + + gk_free((void **)&ubvec, &bestwhere, LTERM); + +} + + + +/*************************************************************************/ +/*! This function computes a k-way partitioning of a graph that minimizes + the specified objective function. + + \param ctrl is the control structure + \param graph is the graph to be partitioned + \param part is the vector that on return will store the partitioning + + \returns the objective value of the partitoning. The partitioning + itself is stored in the part vector. +*/ +/*************************************************************************/ +idx_t BlockKWayPartitioning(ctrl_t *ctrl, graph_t *graph, idx_t *part) +{ + idx_t i, ii, j, nvtxs, objval=0; + idx_t *vwgt; + idx_t nparts, mynparts; + idx_t *fpwgts, *cpwgts, *fpart, *perm; + ipq_t *queue; + + WCOREPUSH; + + nvtxs = graph->nvtxs; + vwgt = graph->vwgt; + + nparts = ctrl->nparts; + + mynparts = gk_min(100*nparts, sqrt(nvtxs)); + + for (i=0; i<nvtxs; i++) + part[i] = i%nparts; + irandArrayPermute(nvtxs, part, 4*nvtxs, 0); + printf("Random cut: %d\n", (int)ComputeCut(graph, part)); + + + /* create the initial multi-section */ + mynparts = GrowMultisection(ctrl, graph, mynparts, part); + + /* balance using label-propagation and refine using a randomized greedy strategy */ + BalanceAndRefineLP(ctrl, graph, mynparts, part); + + + /* determine the size of the fine partitions */ + fpwgts = iset(mynparts, 0, iwspacemalloc(ctrl, mynparts)); + for (i=0; i<nvtxs; i++) + fpwgts[part[i]] += vwgt[i]; + + /* create and initialize the queue that will determine + where to put the next one */ + cpwgts = iset(nparts, 0, iwspacemalloc(ctrl, nparts)); + queue = ipqCreate(nparts); + for (i=0; i<nparts; i++) + ipqInsert(queue, i, 0); + + /* assign the fine partitions into the coarse partitions */ + fpart = iwspacemalloc(ctrl, mynparts); + perm = iwspacemalloc(ctrl, mynparts); + irandArrayPermute(mynparts, perm, mynparts, 1); + for (ii=0; ii<mynparts; ii++) { + i = perm[ii]; + j = ipqSeeTopVal(queue); + fpart[i] = j; + cpwgts[j] += fpwgts[i]; + ipqUpdate(queue, j, -cpwgts[j]); + } + ipqDestroy(queue); + + for (i=0; i<nparts; i++) + printf("cpwgts[%d] = %d\n", (int)i, (int)cpwgts[i]); + + for (i=0; i<nvtxs; i++) + part[i] = fpart[part[i]]; + + WCOREPOP; + + return ComputeCut(graph, part); +} + + +/*************************************************************************/ +/*! This function takes a graph and produces a bisection by using a region + growing algorithm. The resulting bisection is refined using FM. + The resulting partition is returned in graph->where. +*/ +/*************************************************************************/ +idx_t GrowMultisection(ctrl_t *ctrl, graph_t *graph, idx_t nparts, idx_t *where) +{ + idx_t i, j, k, l, nvtxs, nleft, first, last; + idx_t *xadj, *vwgt, *adjncy; + idx_t *queue; + idx_t tvwgt, maxpwgt, *pwgts; + + WCOREPUSH; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->xadj; + adjncy = graph->adjncy; + + queue = iwspacemalloc(ctrl, nvtxs); + + + /* Select the seeds for the nparts-way BFS */ + for (nleft=0, i=0; i<nvtxs; i++) { + if (xadj[i+1]-xadj[i] > 1) /* a seed's degree should be > 1 */ + where[nleft++] = i; + } + nparts = gk_min(nparts, nleft); + for (i=0; i<nparts; i++) { + j = irandInRange(nleft); + queue[i] = where[j]; + where[j] = --nleft; + } + + pwgts = iset(nparts, 0, iwspacemalloc(ctrl, nparts)); + tvwgt = isum(nvtxs, vwgt, 1); + maxpwgt = (1.5*tvwgt)/nparts; + + iset(nvtxs, -1, where); + for (i=0; i<nparts; i++) { + where[queue[i]] = i; + pwgts[i] = vwgt[queue[i]]; + } + + first = 0; + last = nparts; + nleft = nvtxs-nparts; + + + /* Start the BFS from queue to get a partition */ + while (first < last) { + i = queue[first++]; + l = where[i]; + if (pwgts[l] > maxpwgt) + continue; + + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + if (where[k] == -1) { + if (pwgts[l]+vwgt[k] > maxpwgt) + break; + pwgts[l] += vwgt[k]; + where[k] = l; + queue[last++] = k; + nleft--; + } + } + } + + /* Assign the unassigned vertices randomly to the nparts partitions */ + if (nleft > 0) { + for (i=0; i<nvtxs; i++) { + if (where[i] == -1) + where[i] = irandInRange(nparts); + } + } + + WCOREPOP; + + return nparts; +} + + +/*************************************************************************/ +/*! This function balances the partitioning using label propagation. +*/ +/*************************************************************************/ +void BalanceAndRefineLP(ctrl_t *ctrl, graph_t *graph, idx_t nparts, idx_t *where) +{ + idx_t ii, i, j, k, u, v, nvtxs, iter; + idx_t *xadj, *vwgt, *adjncy, *adjwgt; + idx_t tvwgt, *pwgts, maxpwgt, minpwgt; + idx_t *perm; + idx_t from, to, nmoves, nnbrs, *nbrids, *nbrwgts, *nbrmrks; + real_t ubfactor; + + WCOREPUSH; + + nvtxs = graph->nvtxs; + xadj = graph->xadj; + vwgt = graph->vwgt; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + pwgts = iset(nparts, 0, iwspacemalloc(ctrl, nparts)); + + ubfactor = I2RUBFACTOR(ctrl->ufactor); + tvwgt = isum(nvtxs, vwgt, 1); + maxpwgt = (ubfactor*tvwgt)/nparts; + minpwgt = (1.0*tvwgt)/(ubfactor*nparts); + + for (i=0; i<nvtxs; i++) + pwgts[where[i]] += vwgt[i]; + + /* for randomly visiting the vertices */ + perm = iincset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs)); + + /* for keeping track of adjancent partitions */ + nbrids = iwspacemalloc(ctrl, nparts); + nbrwgts = iset(nparts, 0, iwspacemalloc(ctrl, nparts)); + nbrmrks = iset(nparts, -1, iwspacemalloc(ctrl, nparts)); + + /* perform a fixed number of balancing LP iterations */ + if (ctrl->dbglvl&METIS_DBG_REFINE) + printf("BLP: nparts: %"PRIDX", min-max: [%"PRIDX", %"PRIDX"], bal: %7.4"PRREAL", cut: %9"PRIDX"\n", + nparts, minpwgt, maxpwgt, 1.0*imax(nparts, pwgts, 1)*nparts/tvwgt, ComputeCut(graph, where)); + for (iter=0; iter<ctrl->niter; iter++) { + if (imax(nparts, pwgts, 1)*nparts < ubfactor*tvwgt) + break; + + irandArrayPermute(nvtxs, perm, nvtxs/8, 1); + nmoves = 0; + + for (ii=0; ii<nvtxs; ii++) { + u = perm[ii]; + + from = where[u]; + if (pwgts[from] - vwgt[u] < minpwgt) + continue; + + nnbrs = 0; + for (j=xadj[u]; j<xadj[u+1]; j++) { + v = adjncy[j]; + to = where[v]; + + if (pwgts[to] + vwgt[u] > maxpwgt) + continue; /* skip if 'to' is overweight */ + + if ((k = nbrmrks[to]) == -1) { + nbrmrks[to] = k = nnbrs++; + nbrids[k] = to; + } + nbrwgts[k] += xadj[v+1]-xadj[v]; + } + if (nnbrs == 0) + continue; + + to = nbrids[iargmax(nnbrs, nbrwgts, 1)]; + if (from != to) { + where[u] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt[u]); + nmoves++; + } + + for (k=0; k<nnbrs; k++) { + nbrmrks[nbrids[k]] = -1; + nbrwgts[k] = 0; + } + + } + + if (ctrl->dbglvl&METIS_DBG_REFINE) + printf(" nmoves: %8"PRIDX", bal: %7.4"PRREAL", cut: %9"PRIDX"\n", + nmoves, 1.0*imax(nparts, pwgts, 1)*nparts/tvwgt, ComputeCut(graph, where)); + + if (nmoves == 0) + break; + } + + /* perform a fixed number of refinement LP iterations */ + if (ctrl->dbglvl&METIS_DBG_REFINE) + printf("RLP: nparts: %"PRIDX", min-max: [%"PRIDX", %"PRIDX"], bal: %7.4"PRREAL", cut: %9"PRIDX"\n", + nparts, minpwgt, maxpwgt, 1.0*imax(nparts, pwgts, 1)*nparts/tvwgt, ComputeCut(graph, where)); + for (iter=0; iter<ctrl->niter; iter++) { + irandArrayPermute(nvtxs, perm, nvtxs/8, 1); + nmoves = 0; + + for (ii=0; ii<nvtxs; ii++) { + u = perm[ii]; + + from = where[u]; + if (pwgts[from] - vwgt[u] < minpwgt) + continue; + + nnbrs = 0; + for (j=xadj[u]; j<xadj[u+1]; j++) { + v = adjncy[j]; + to = where[v]; + + if (to != from && pwgts[to] + vwgt[u] > maxpwgt) + continue; /* skip if 'to' is overweight */ + + if ((k = nbrmrks[to]) == -1) { + nbrmrks[to] = k = nnbrs++; + nbrids[k] = to; + } + nbrwgts[k] += adjwgt[j]; + } + if (nnbrs == 0) + continue; + + to = nbrids[iargmax(nnbrs, nbrwgts, 1)]; + if (from != to) { + where[u] = to; + INC_DEC(pwgts[to], pwgts[from], vwgt[u]); + nmoves++; + } + + for (k=0; k<nnbrs; k++) { + nbrmrks[nbrids[k]] = -1; + nbrwgts[k] = 0; + } + + } + + if (ctrl->dbglvl&METIS_DBG_REFINE) + printf(" nmoves: %8"PRIDX", bal: %7.4"PRREAL", cut: %9"PRIDX"\n", + nmoves, 1.0*imax(nparts, pwgts, 1)*nparts/tvwgt, ComputeCut(graph, where)); + + if (nmoves == 0) + break; + } + + WCOREPOP; +} + + +/*************************************************************************/ +/*! This uses Metis' routines for balancing and refining the multi-BFS + solution. +*/ +/*************************************************************************/ +void BalanceAndRefine(ctrl_t *origctrl, graph_t *graph, idx_t nparts, idx_t *where) +{ + idx_t i; + idx_t options[METIS_NOPTIONS]; + ctrl_t *ctrl; + + FreeWorkSpace(origctrl); + + METIS_SetDefaultOptions(options); + options[METIS_OPTION_NITER] = origctrl->niter; + options[METIS_OPTION_DBGLVL] = origctrl->dbglvl; + options[METIS_OPTION_UFACTOR] = origctrl->ufactor; + options[METIS_OPTION_OBJTYPE] = METIS_OBJTYPE_CUT; + + ctrl = SetupCtrl(METIS_OP_KMETIS, options, 1, nparts, NULL, NULL); + + AllocateWorkSpace(ctrl, graph); + AllocateRefinementWorkSpace(ctrl, 2*graph->nedges); + + AllocateKWayPartitionMemory(ctrl, graph); + icopy(graph->nvtxs, where, graph->where); + + ComputeKWayPartitionParams(ctrl, graph); + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(origctrl->RefTmr)); + + SetupKWayBalMultipliers(ctrl, graph); + + if (!IsBalanced(ctrl, graph, .02)) { + ComputeKWayBoundary(ctrl, graph, BNDTYPE_BALANCE); + Greedy_KWayOptimize(ctrl, graph, 1, 0, OMODE_BALANCE); + ComputeKWayBoundary(ctrl, graph, BNDTYPE_REFINE); + } + + Greedy_KWayOptimize(ctrl, graph, ctrl->niter, 5.0, OMODE_REFINE); + icopy(graph->nvtxs, graph->where, where); + + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(origctrl->RefTmr)); + + FreeRData(graph); + FreeCtrl(&ctrl); + + AllocateWorkSpace(origctrl, graph); +} + + diff --git a/3rdParty/metis/metis-5.1.0/libmetis/kwayfm.c b/3rdParty/metis/metis-5.1.1/libmetis/kwayfm.c similarity index 67% rename from 3rdParty/metis/metis-5.1.0/libmetis/kwayfm.c rename to 3rdParty/metis/metis-5.1.1/libmetis/kwayfm.c index dedfd39098c40836f60f9b6ca3895e2293c89f29..365dbad8ba07b98b9df8d6d2de6fa6e422809bef 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/kwayfm.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/kwayfm.c @@ -5,7 +5,7 @@ \date Started 7/28/97 \author George \author Copyright 1997-2009, Regents of the University of Minnesota -\version $Id: kwayfm.c 10567 2011-07-13 16:17:07Z karypis $ +\version $Id: kwayfm.c 17513 2014-08-05 16:20:50Z dominique $ */ #include "metislib.h" @@ -57,18 +57,19 @@ void Greedy_KWayOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, */ /**************************************************************************/ -void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, +void Greedy_KWayCutOptimize0(ctrl_t *ctrl, graph_t *graph, idx_t niter, real_t ffactor, idx_t omode) { /* Common variables to all types of kway-refinement/balancing routines */ idx_t i, ii, iii, j, k, l, pass, nvtxs, nparts, gain; idx_t from, me, to, oldcut, vwgt; idx_t *xadj, *adjncy, *adjwgt; - idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts; + idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minpwgts, *maxpwgts; idx_t nmoved, nupd, *vstatus, *updptr, *updind; idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL; idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL; idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE); + real_t *tpwgts, ubfactor; /* Edgecut-specific/different variables */ idx_t nbnd, oldnnbrs; @@ -77,6 +78,7 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, ckrinfo_t *myrinfo; cnbr_t *mynbrs; + ffactor = 0.0; WCOREPUSH; /* Link the graph fields */ @@ -92,17 +94,23 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, pwgts = graph->pwgts; nparts = ctrl->nparts; + tpwgts = ctrl->tpwgts; /* Setup the weight intervals of the various subdomains */ - minwgt = iwspacemalloc(ctrl, nparts); - maxwgt = iwspacemalloc(ctrl, nparts); - itpwgts = iwspacemalloc(ctrl, nparts); + minpwgts = iwspacemalloc(ctrl, nparts+2); + maxpwgts = iwspacemalloc(ctrl, nparts+2); + + if (omode == OMODE_BALANCE) + ubfactor = ctrl->ubfactors[0]; + else + ubfactor = gk_max(ctrl->ubfactors[0], ComputeLoadImbalance(graph, nparts, ctrl->pijbm)); for (i=0; i<nparts; i++) { - itpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0]; - maxwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*ctrl->ubfactors[0]; - minwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*(1.0/ctrl->ubfactors[0]); + maxpwgts[i] = tpwgts[i]*graph->tvwgt[0]*ubfactor; + minpwgts[i] = tpwgts[i]*graph->tvwgt[0]*(1.0/ubfactor); } + maxpwgts[nparts] = maxpwgts[nparts+1] = 0; + minpwgts[nparts] = minpwgts[nparts+1] = 0; perm = iwspacemalloc(ctrl, nvtxs); @@ -111,7 +119,8 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, control the subdomains to which moves are allowed to be made. When ctrl->minconn is false, the default values of 2 allow all moves to go through and it does not interfere with the zero-gain move selection. */ - safetos = iset(nparts, 2, iwspacemalloc(ctrl, nparts)); + safetos = iset(nparts+2, 2, iwspacemalloc(ctrl, nparts+2)); + safetos[nparts] = safetos[nparts+1] = 0; if (ctrl->minconn) { ComputeSubDomainGraph(ctrl, graph); @@ -140,11 +149,11 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, printf("%s: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"," " Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX, (omode == OMODE_REFINE ? "GRC" : "GBC"), - pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), minwgt[0], maxwgt[0], + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), minpwgts[0], maxpwgts[0], ComputeLoadImbalance(graph, nparts, ctrl->pijbm), graph->nvtxs, graph->nbnd, graph->mincut); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -158,11 +167,11 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (omode == OMODE_BALANCE) { /* Check to see if things are out of balance, given the tolerance */ - for (i=0; i<nparts; i++) { - if (pwgts[i] > maxwgt[i]) + for (i=0; i<nparts+2; i++) { + if (pwgts[i] > maxpwgts[i] || pwgts[i] < minpwgts[i]) break; } - if (i == nparts) /* Things are balanced. Return right away */ + if (i == nparts+2) /* Things are balanced. Return right away */ break; } @@ -171,7 +180,7 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, nupd = 0; if (ctrl->minconn) - maxndoms = imax(nparts, nads); + maxndoms = imax(nparts, nads,1); /* Insert the boundary vertices in the priority queue */ irandArrayPermute(nbnd, perm, nbnd/4, 1); @@ -199,11 +208,11 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, /* Prevent moves that make 'from' domain underbalanced */ if (omode == OMODE_REFINE) { - if (myrinfo->id > 0 && pwgts[from]-vwgt < minwgt[from]) + if (myrinfo->id > 0 && pwgts[from]-vwgt < minpwgts[from]) continue; } else { /* OMODE_BALANCE */ - if (pwgts[from]-vwgt < minwgt[from]) + if (pwgts[from]-vwgt < minpwgts[from]) continue; } @@ -219,7 +228,7 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (!safetos[to=mynbrs[k].pid]) continue; gain = mynbrs[k].ed-myrinfo->id; - if (gain >= 0 && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain) + if (gain >= 0 && pwgts[to]+vwgt <= maxpwgts[to]+ffactor*gain) break; } if (k < 0) @@ -229,10 +238,10 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (!safetos[to=mynbrs[j].pid]) continue; gain = mynbrs[j].ed-myrinfo->id; - if ((mynbrs[j].ed > mynbrs[k].ed && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain) + if ((mynbrs[j].ed > mynbrs[k].ed && pwgts[to]+vwgt <= maxpwgts[to]+ffactor*gain) || (mynbrs[j].ed == mynbrs[k].ed && - itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid])) + tpwgts[mynbrs[k].pid]*pwgts[to] < tpwgts[to]*pwgts[mynbrs[k].pid])) k = j; } @@ -241,8 +250,8 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, gain = mynbrs[k].ed-myrinfo->id; if (!(gain > 0 || (gain == 0 - && (pwgts[from] >= maxwgt[from] - || itpwgts[to]*pwgts[from] > itpwgts[from]*(pwgts[to]+vwgt) + && (pwgts[from] >= maxpwgts[from] + || tpwgts[to]*pwgts[from] > tpwgts[from]*(pwgts[to]+vwgt) || (iii%2 == 0 && safetos[to] == 2) ) ) @@ -254,8 +263,8 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, for (k=myrinfo->nnbrs-1; k>=0; k--) { if (!safetos[to=mynbrs[k].pid]) continue; - if (pwgts[to]+vwgt <= maxwgt[to] || - itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + if (pwgts[to]+vwgt <= maxpwgts[to] || + tpwgts[from]*(pwgts[to]+vwgt) <= tpwgts[to]*pwgts[from]) break; } if (k < 0) @@ -264,18 +273,357 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, for (j=k-1; j>=0; j--) { if (!safetos[to=mynbrs[j].pid]) continue; - if (itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid]) + if (tpwgts[mynbrs[k].pid]*pwgts[to] < tpwgts[to]*pwgts[mynbrs[k].pid]) k = j; } to = mynbrs[k].pid; - if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && + if (pwgts[from] < maxpwgts[from] && pwgts[to] > minpwgts[to] && mynbrs[k].ed-myrinfo->id < 0) continue; } + /*===================================================================== + * If we got here, we can now move the vertex from 'from' to 'to' + *======================================================================*/ + graph->mincut -= mynbrs[k].ed-myrinfo->id; + nmoved++; + + IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO, + printf("\t\tMoving %6"PRIDX" from %3"PRIDX"/%"PRIDX" to %3"PRIDX"/%"PRIDX" [%6"PRIDX" %6"PRIDX"]. Gain: %4"PRIDX". Cut: %6"PRIDX"\n", + i, from, safetos[from], to, safetos[to], pwgts[from], pwgts[to], mynbrs[k].ed-myrinfo->id, graph->mincut)); + + /* Update the subdomain connectivity information */ + if (ctrl->minconn) { + /* take care of i's move itself */ + UpdateEdgeSubDomainGraph(ctrl, from, to, myrinfo->id-mynbrs[k].ed, &maxndoms); + + /* take care of the adjancent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + me = where[adjncy[j]]; + if (me != from && me != to) { + UpdateEdgeSubDomainGraph(ctrl, from, me, -adjwgt[j], &maxndoms); + UpdateEdgeSubDomainGraph(ctrl, to, me, adjwgt[j], &maxndoms); + } + } + } + + /* Update ID/ED and BND related information for the moved vertex */ + INC_DEC(pwgts[to], pwgts[from], vwgt); + UpdateMovedVertexInfoAndBND(i, from, k, to, myrinfo, mynbrs, where, nbnd, + bndptr, bndind, bndtype); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[i]; j<xadj[i+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + myrinfo = graph->ckrinfo+ii; + + oldnnbrs = myrinfo->nnbrs; + + UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me, + from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, bndtype); + + UpdateQueueInfo(queue, vstatus, ii, me, from, to, myrinfo, oldnnbrs, + nupd, updptr, updind, bndtype); + + ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]); + } + + } + + graph->nbnd = nbnd; + + /* Reset the vstatus and associated data structures */ + for (i=0; i<nupd; i++) { + ASSERT(updptr[updind[i]] != -1); + ASSERT(vstatus[updind[i]] != VPQSTATUS_NOTPRESENT); + vstatus[updind[i]] = VPQSTATUS_NOTPRESENT; + updptr[updind[i]] = -1; + } + + if (ctrl->dbglvl&METIS_DBG_REFINE) { + printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"." + " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX, + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), + ComputeLoadImbalance(graph, nparts, ctrl->pijbm), + graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where)); + if (ctrl->minconn) + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); + printf("\n"); + } + + if (nmoved == 0 || (omode == OMODE_REFINE && graph->mincut == oldcut)) + break; + } + + rpqDestroy(queue); + + WCOREPOP; +} + + +/*************************************************************************/ +/*! K-way partitioning optimization in which the vertices are visited in + decreasing ed/sqrt(nnbrs)-id order. Note this is just an + approximation, as the ed is often split across different subdomains + and the sqrt(nnbrs) is just a crude approximation. + + \param graph is the graph that is being refined. + \param niter is the number of refinement iterations. + \param ffactor is the \em fudge-factor for allowing positive gain moves + to violate the max-pwgt constraint. + \param omode is the type of optimization that will performed among + OMODE_REFINE and OMODE_BALANCE + + +*/ +/**************************************************************************/ +void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, + real_t ffactor, idx_t omode) +{ + /* Common variables to all types of kway-refinement/balancing routines */ + idx_t i, ii, iii, j, k, l, pass, nvtxs, nparts, gain; + idx_t from, me, to, oldcut, vwgt; + idx_t *xadj, *adjncy, *adjwgt; + idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minpwgts, *maxpwgts; + idx_t nmoved, nupd, *vstatus, *updptr, *updind; + idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL; + idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL; + idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE); + real_t *tpwgts, ubfactor; + + /* Edgecut-specific/different variables */ + idx_t nbnd, oldnnbrs; + rpq_t *queue; + real_t rgain; + ckrinfo_t *myrinfo; + cnbr_t *mynbrs; + + ffactor = 0.0; + WCOREPUSH; + + /* Link the graph fields */ + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + nparts = ctrl->nparts; + tpwgts = ctrl->tpwgts; + + /* Setup the weight intervals of the various subdomains */ + minpwgts = iwspacemalloc(ctrl, nparts+2); + maxpwgts = iwspacemalloc(ctrl, nparts+2); + + if (omode == OMODE_BALANCE) + ubfactor = ctrl->ubfactors[0]; + else + ubfactor = gk_max(ctrl->ubfactors[0], ComputeLoadImbalance(graph, nparts, ctrl->pijbm)); + + for (i=0; i<nparts; i++) { + maxpwgts[i] = tpwgts[i]*graph->tvwgt[0]*ubfactor; + minpwgts[i] = tpwgts[i]*graph->tvwgt[0]*(1.0/ubfactor); + } + maxpwgts[nparts] = maxpwgts[nparts+1] = 0; + minpwgts[nparts] = minpwgts[nparts+1] = 0; + + perm = iwspacemalloc(ctrl, nvtxs); + + + /* This stores the valid target subdomains. It is used when ctrl->minconn to + control the subdomains to which moves are allowed to be made. + When ctrl->minconn is false, the default values of 2 allow all moves to + go through and it does not interfere with the zero-gain move selection. */ + safetos = iset(nparts+2, 2, iwspacemalloc(ctrl, nparts+2)); + safetos[nparts] = safetos[nparts+1] = 0; + + if (ctrl->minconn) { + ComputeSubDomainGraph(ctrl, graph); + + nads = ctrl->nads; + adids = ctrl->adids; + adwgts = ctrl->adwgts; + doms = iset(nparts, 0, ctrl->pvec1); + } + + + /* Setup updptr, updind like boundary info to keep track of the vertices whose + vstatus's need to be reset at the end of the inner iteration */ + vstatus = iset(nvtxs, VPQSTATUS_NOTPRESENT, iwspacemalloc(ctrl, nvtxs)); + updptr = iset(nvtxs, -1, iwspacemalloc(ctrl, nvtxs)); + updind = iwspacemalloc(ctrl, nvtxs); + + if (ctrl->contig) { + /* The arrays that will be used for limited check of articulation points */ + bfslvl = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs)); + bfsind = iwspacemalloc(ctrl, nvtxs); + bfsmrk = iset(nvtxs, 0, iwspacemalloc(ctrl, nvtxs)); + } + + if (ctrl->dbglvl&METIS_DBG_REFINE) { + printf("%s: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"," + " Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX, + (omode == OMODE_REFINE ? "GRC" : "GBC"), + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), minpwgts[0], maxpwgts[0], + ComputeLoadImbalance(graph, nparts, ctrl->pijbm), + graph->nvtxs, graph->nbnd, graph->mincut); + if (ctrl->minconn) + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); + printf("\n"); + } + + queue = rpqCreate(nvtxs); + + /*===================================================================== + * The top-level refinement loop + *======================================================================*/ + for (pass=0; pass<niter; pass++) { + ASSERT(ComputeCut(graph, where) == graph->mincut); + + if (omode == OMODE_BALANCE) { + /* Check to see if things are out of balance, given the tolerance */ + for (i=0; i<nparts+2; i++) { + if (pwgts[i] > maxpwgts[i] || pwgts[i] < minpwgts[i]) + break; + } + if (i == nparts+2) /* Things are balanced. Return right away */ + break; + } + + oldcut = graph->mincut; + nbnd = graph->nbnd; + nupd = 0; + + if (ctrl->minconn) + maxndoms = imax(nparts, nads,1); + + /* Insert the boundary vertices in the priority queue */ + irandArrayPermute(nbnd, perm, nbnd/4, 1); + for (ii=0; ii<nbnd; ii++) { + i = bndind[perm[ii]]; + rgain = (graph->ckrinfo[i].nnbrs > 0 ? + 1.0*graph->ckrinfo[i].ed/sqrt(graph->ckrinfo[i].nnbrs) : 0.0) + - graph->ckrinfo[i].id; + rpqInsert(queue, i, rgain); + vstatus[i] = VPQSTATUS_PRESENT; + ListInsert(nupd, updind, updptr, i); + } + + /* Start extracting vertices from the queue and try to move them */ + for (nmoved=0, iii=0;;iii++) { + if ((i = rpqGetTop(queue)) == -1) + break; + vstatus[i] = VPQSTATUS_EXTRACTED; + + myrinfo = graph->ckrinfo+i; + mynbrs = ctrl->cnbrpool + myrinfo->inbr; + + from = where[i]; + vwgt = graph->vwgt[i]; + +#ifdef XXX + /* Prevent moves that make 'from' domain underbalanced */ + if (omode == OMODE_REFINE) { + if (myrinfo->id > 0 && pwgts[from]-vwgt < minpwgts[from]) + continue; + } + else { /* OMODE_BALANCE */ + if (pwgts[from]-vwgt < minpwgts[from]) + continue; + } +#endif + + if (ctrl->contig && IsArticulationNode(i, xadj, adjncy, where, bfslvl, bfsind, bfsmrk)) + continue; + + if (ctrl->minconn) + SelectSafeTargetSubdomains(myrinfo, mynbrs, nads, adids, maxndoms, safetos, doms); + + /* Find the most promising subdomain to move to */ + if (omode == OMODE_REFINE) { + for (k=myrinfo->nnbrs-1; k>=0; k--) { + if (!safetos[to=mynbrs[k].pid]) + continue; + if (((mynbrs[k].ed > myrinfo->id) && + ((pwgts[from]-vwgt >= minpwgts[from]) || + (tpwgts[from]*pwgts[to] < tpwgts[to]*(pwgts[from]-vwgt))) && + ((pwgts[to]+vwgt <= maxpwgts[to]) || + (tpwgts[from]*pwgts[to] < tpwgts[to]*(pwgts[from]-vwgt))) + ) || + ((mynbrs[k].ed == myrinfo->id) && + (tpwgts[from]*pwgts[to] < tpwgts[to]*(pwgts[from]-vwgt))) + ) + break; + } + if (k < 0) + continue; /* break out if you did not find a candidate */ + + for (j=k-1; j>=0; j--) { + if (!safetos[to=mynbrs[j].pid]) + continue; + if (((mynbrs[j].ed > mynbrs[k].ed) && + ((pwgts[from]-vwgt >= minpwgts[from]) || + (tpwgts[from]*pwgts[to] < tpwgts[to]*(pwgts[from]-vwgt))) && + ((pwgts[to]+vwgt <= maxpwgts[to]) || + (tpwgts[from]*pwgts[to] < tpwgts[to]*(pwgts[from]-vwgt))) + ) || + ((mynbrs[j].ed == mynbrs[k].ed) && + (tpwgts[mynbrs[k].pid]*pwgts[to] < tpwgts[to]*pwgts[mynbrs[k].pid])) + ) + k = j; + } + + to = mynbrs[k].pid; + + gain = mynbrs[k].ed-myrinfo->id; + /* + if (!(gain > 0 + || (gain == 0 + && (pwgts[from] >= maxpwgts[from] + || tpwgts[to]*pwgts[from] > tpwgts[from]*(pwgts[to]+vwgt) + || (iii%2 == 0 && safetos[to] == 2) + ) + ) + ) + ) + continue; + */ + } + else { /* OMODE_BALANCE */ + for (k=myrinfo->nnbrs-1; k>=0; k--) { + if (!safetos[to=mynbrs[k].pid]) + continue; + /* the correctness of the following test follows from the correctness + of the similar test in the subsequent loop */ + if (from >= nparts || tpwgts[from]*pwgts[to] < tpwgts[to]*(pwgts[from]-vwgt)) + break; + } + if (k < 0) + continue; /* break out if you did not find a candidate */ + + for (j=k-1; j>=0; j--) { + if (!safetos[to=mynbrs[j].pid]) + continue; + if (tpwgts[mynbrs[k].pid]*pwgts[to] < tpwgts[to]*pwgts[mynbrs[k].pid]) + k = j; + } + + to = mynbrs[k].pid; + + //if (pwgts[from] < maxpwgts[from] && pwgts[to] > minpwgts[to] && + // mynbrs[k].ed-myrinfo->id < 0) + // continue; + } + /*===================================================================== * If we got here, we can now move the vertex from 'from' to 'to' @@ -284,8 +632,8 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, nmoved++; IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO, - printf("\t\tMoving %6"PRIDX" to %3"PRIDX". Gain: %4"PRIDX". Cut: %6"PRIDX"\n", - i, to, mynbrs[k].ed-myrinfo->id, graph->mincut)); + printf("\t\tMoving %6"PRIDX" from %3"PRIDX"/%"PRIDX" to %3"PRIDX"/%"PRIDX" [%6"PRIDX" %6"PRIDX"]. Gain: %4"PRIDX". Cut: %6"PRIDX"\n", + i, from, safetos[from], to, safetos[to], pwgts[from], pwgts[to], mynbrs[k].ed-myrinfo->id, graph->mincut)); /* Update the subdomain connectivity information */ if (ctrl->minconn) { @@ -323,6 +671,7 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]); } + } graph->nbnd = nbnd; @@ -338,11 +687,11 @@ void Greedy_KWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (ctrl->dbglvl&METIS_DBG_REFINE) { printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"." " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX, - pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), ComputeLoadImbalance(graph, nparts, ctrl->pijbm), graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where)); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -374,11 +723,12 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, idx_t i, ii, iii, j, k, l, pass, nvtxs, nparts, gain; idx_t from, me, to, oldcut, vwgt; idx_t *xadj, *adjncy; - idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt, *itpwgts; + idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minpwgts, *maxpwgts; idx_t nmoved, nupd, *vstatus, *updptr, *updind; idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL; idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL; idx_t bndtype = (omode == OMODE_REFINE ? BNDTYPE_REFINE : BNDTYPE_BALANCE); + real_t *tpwgts; /* Volume-specific/different variables */ ipq_t *queue; @@ -399,16 +749,15 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, pwgts = graph->pwgts; nparts = ctrl->nparts; + tpwgts = ctrl->tpwgts; /* Setup the weight intervals of the various subdomains */ - minwgt = iwspacemalloc(ctrl, nparts); - maxwgt = iwspacemalloc(ctrl, nparts); - itpwgts = iwspacemalloc(ctrl, nparts); + minpwgts = iwspacemalloc(ctrl, nparts); + maxpwgts = iwspacemalloc(ctrl, nparts); for (i=0; i<nparts; i++) { - itpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0]; - maxwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*ctrl->ubfactors[0]; - minwgt[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*(1.0/ctrl->ubfactors[0]); + maxpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*ctrl->ubfactors[0]; + minpwgts[i] = ctrl->tpwgts[i]*graph->tvwgt[0]*(1.0/ctrl->ubfactors[0]); } perm = iwspacemalloc(ctrl, nvtxs); @@ -452,11 +801,11 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, printf("%s: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL ", Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %5"PRIDX", Vol: %5"PRIDX, (omode == OMODE_REFINE ? "GRV" : "GBV"), - pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), minwgt[0], maxwgt[0], + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), minpwgts[0], maxpwgts[0], ComputeLoadImbalance(graph, nparts, ctrl->pijbm), graph->nvtxs, graph->nbnd, graph->mincut, graph->minvol); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -472,7 +821,7 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (omode == OMODE_BALANCE) { /* Check to see if things are out of balance, given the tolerance */ for (i=0; i<nparts; i++) { - if (pwgts[i] > maxwgt[i]) + if (pwgts[i] > maxpwgts[i]) break; } if (i == nparts) /* Things are balanced. Return right away */ @@ -484,7 +833,7 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, nupd = 0; if (ctrl->minconn) - maxndoms = imax(nparts, nads); + maxndoms = imax(nparts, nads,1); /* Insert the boundary vertices in the priority queue */ irandArrayPermute(graph->nbnd, perm, graph->nbnd/4, 1); @@ -509,11 +858,11 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, /* Prevent moves that make 'from' domain underbalanced */ if (omode == OMODE_REFINE) { - if (myrinfo->nid > 0 && pwgts[from]-vwgt < minwgt[from]) + if (myrinfo->nid > 0 && pwgts[from]-vwgt < minpwgts[from]) continue; } else { /* OMODE_BALANCE */ - if (pwgts[from]-vwgt < minwgt[from]) + if (pwgts[from]-vwgt < minpwgts[from]) continue; } @@ -531,7 +880,7 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (!safetos[to=mynbrs[k].pid]) continue; gain = mynbrs[k].gv + xgain; - if (gain >= 0 && pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain) + if (gain >= 0 && pwgts[to]+vwgt <= maxpwgts[to]+ffactor*gain) break; } if (k < 0) @@ -542,15 +891,15 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, continue; gain = mynbrs[j].gv + xgain; if ((mynbrs[j].gv > mynbrs[k].gv && - pwgts[to]+vwgt <= maxwgt[to]+ffactor*gain) + pwgts[to]+vwgt <= maxpwgts[to]+ffactor*gain) || (mynbrs[j].gv == mynbrs[k].gv && mynbrs[j].ned > mynbrs[k].ned && - pwgts[to]+vwgt <= maxwgt[to]) + pwgts[to]+vwgt <= maxpwgts[to]) || (mynbrs[j].gv == mynbrs[k].gv && mynbrs[j].ned == mynbrs[k].ned && - itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid]) + tpwgts[mynbrs[k].pid]*pwgts[to] < tpwgts[to]*pwgts[mynbrs[k].pid]) ) k = j; } @@ -563,8 +912,8 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, j = 1; else if (mynbrs[k].ned-myrinfo->nid == 0) { if ((iii%2 == 0 && safetos[to] == 2) || - pwgts[from] >= maxwgt[from] || - itpwgts[from]*(pwgts[to]+vwgt) < itpwgts[to]*pwgts[from]) + pwgts[from] >= maxpwgts[from] || + tpwgts[from]*(pwgts[to]+vwgt) < tpwgts[to]*pwgts[from]) j = 1; } if (j == 0) @@ -574,8 +923,8 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, for (k=myrinfo->nnbrs-1; k>=0; k--) { if (!safetos[to=mynbrs[k].pid]) continue; - if (pwgts[to]+vwgt <= maxwgt[to] || - itpwgts[from]*(pwgts[to]+vwgt) <= itpwgts[to]*pwgts[from]) + if (pwgts[to]+vwgt <= maxpwgts[to] || + tpwgts[from]*(pwgts[to]+vwgt) <= tpwgts[to]*pwgts[from]) break; } if (k < 0) @@ -584,12 +933,12 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, for (j=k-1; j>=0; j--) { if (!safetos[to=mynbrs[j].pid]) continue; - if (itpwgts[mynbrs[k].pid]*pwgts[to] < itpwgts[to]*pwgts[mynbrs[k].pid]) + if (tpwgts[mynbrs[k].pid]*pwgts[to] < tpwgts[to]*pwgts[mynbrs[k].pid]) k = j; } to = mynbrs[k].pid; - if (pwgts[from] < maxwgt[from] && pwgts[to] > minwgt[to] && + if (pwgts[from] < maxpwgts[from] && pwgts[to] > minpwgts[to] && (xgain+mynbrs[k].gv < 0 || (xgain+mynbrs[k].gv == 0 && mynbrs[k].ned-myrinfo->nid < 0)) ) @@ -646,11 +995,11 @@ void Greedy_KWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (ctrl->dbglvl&METIS_DBG_REFINE) { printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"." " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX, - pwgts[iargmin(nparts, pwgts)], imax(nparts, pwgts), + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), ComputeLoadImbalance(graph, nparts, ctrl->pijbm), graph->nbnd, nmoved, graph->mincut, graph->minvol); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -688,7 +1037,7 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, idx_t i, ii, iii, j, k, l, pass, nvtxs, ncon, nparts, gain; idx_t from, me, to, cto, oldcut; idx_t *xadj, *vwgt, *adjncy, *adjwgt; - idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt; + idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minpwgts, *maxpwgts; idx_t nmoved, nupd, *vstatus, *updptr, *updind; idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL; idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL; @@ -740,14 +1089,14 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, /* Setup the weight intervals of the various subdomains */ - minwgt = iwspacemalloc(ctrl, nparts*ncon); - maxwgt = iwspacemalloc(ctrl, nparts*ncon); + minpwgts = iwspacemalloc(ctrl, nparts*ncon); + maxpwgts = iwspacemalloc(ctrl, nparts*ncon); for (i=0; i<nparts; i++) { for (j=0; j<ncon; j++) { - maxwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j]; - /*minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]);*/ - minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2; + maxpwgts[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j]; + /*minpwgts[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]);*/ + minpwgts[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2; } } @@ -787,11 +1136,11 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, printf("%s: [%6"PRIDX" %6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"(%.3"PRREAL")," " Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX", (%"PRIDX")", (omode == OMODE_REFINE ? "GRC" : "GBC"), - imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), imax(nparts*ncon, maxwgt), + imin(nparts*ncon, pwgts,1), imax(nparts*ncon, pwgts,1), imax(nparts*ncon, maxpwgts,1), ComputeLoadImbalance(graph, nparts, pijbm), origbal, graph->nvtxs, graph->nbnd, graph->mincut, niter); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -813,7 +1162,7 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, nupd = 0; if (ctrl->minconn) - maxndoms = imax(nparts, nads); + maxndoms = imax(nparts, nads,1); /* Insert the boundary vertices in the priority queue */ irandArrayPermute(nbnd, perm, nbnd/4, 1); @@ -841,11 +1190,11 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, /* Prevent moves that make 'from' domain underbalanced */ if (omode == OMODE_REFINE) { if (myrinfo->id > 0 && - !ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon)) + !ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minpwgts+from*ncon)) continue; } else { /* OMODE_BALANCE */ - if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon)) + if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minpwgts+from*ncon)) continue; } @@ -861,7 +1210,7 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (!safetos[to=mynbrs[k].pid]) continue; gain = mynbrs[k].ed-myrinfo->id; - if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon)) + if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxpwgts+to*ncon)) break; } if (k < 0) @@ -872,7 +1221,7 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (!safetos[to=mynbrs[j].pid]) continue; if ((mynbrs[j].ed > mynbrs[k].ed && - ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon)) + ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxpwgts+to*ncon)) || (mynbrs[j].ed == mynbrs[k].ed && BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors, @@ -901,7 +1250,7 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, for (k=myrinfo->nnbrs-1; k>=0; k--) { if (!safetos[to=mynbrs[k].pid]) continue; - if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon) || + if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxpwgts+to*ncon) || BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors, -1, pwgts+from*ncon, pijbm+from*ncon, +1, pwgts+to*ncon, pijbm+to*ncon)) @@ -994,11 +1343,11 @@ void Greedy_McKWayCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (ctrl->dbglvl&METIS_DBG_REFINE) { printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"." " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX, - imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), + imin(nparts*ncon, pwgts,1), imax(nparts*ncon, pwgts,1), ComputeLoadImbalance(graph, nparts, pijbm), graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where)); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -1030,7 +1379,7 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, idx_t i, ii, iii, j, k, l, pass, nvtxs, ncon, nparts, gain; idx_t from, me, to, cto, oldcut; idx_t *xadj, *vwgt, *adjncy; - idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minwgt, *maxwgt; + idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minpwgts, *maxpwgts; idx_t nmoved, nupd, *vstatus, *updptr, *updind; idx_t maxndoms, *safetos=NULL, *nads=NULL, *doms=NULL, **adids=NULL, **adwgts=NULL; idx_t *bfslvl=NULL, *bfsind=NULL, *bfsmrk=NULL; @@ -1079,14 +1428,14 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, /* Setup the weight intervals of the various subdomains */ - minwgt = iwspacemalloc(ctrl, nparts*ncon); - maxwgt = iwspacemalloc(ctrl, nparts*ncon); + minpwgts = iwspacemalloc(ctrl, nparts*ncon); + maxpwgts = iwspacemalloc(ctrl, nparts*ncon); for (i=0; i<nparts; i++) { for (j=0; j<ncon; j++) { - maxwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j]; - /*minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]); */ - minwgt[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2; + maxpwgts[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*ubfactors[j]; + /*minpwgts[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*(.9/ubfactors[j]); */ + minpwgts[i*ncon+j] = ctrl->tpwgts[i*ncon+j]*graph->tvwgt[j]*.2; } } @@ -1131,11 +1480,11 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, printf("%s: [%6"PRIDX" %6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"(%.3"PRREAL")," ", Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %5"PRIDX", Vol: %5"PRIDX", (%"PRIDX")", (omode == OMODE_REFINE ? "GRV" : "GBV"), - imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), imax(nparts*ncon, maxwgt), + imin(nparts*ncon, pwgts,1), imax(nparts*ncon, pwgts,1), imax(nparts*ncon, maxpwgts,1), ComputeLoadImbalance(graph, nparts, pijbm), origbal, graph->nvtxs, graph->nbnd, graph->mincut, graph->minvol, niter); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -1157,7 +1506,7 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, nupd = 0; if (ctrl->minconn) - maxndoms = imax(nparts, nads); + maxndoms = imax(nparts, nads,1); /* Insert the boundary vertices in the priority queue */ irandArrayPermute(graph->nbnd, perm, graph->nbnd/4, 1); @@ -1182,11 +1531,11 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, /* Prevent moves that make 'from' domain underbalanced */ if (omode == OMODE_REFINE) { if (myrinfo->nid > 0 && - !ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon)) + !ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minpwgts+from*ncon)) continue; } else { /* OMODE_BALANCE */ - if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minwgt+from*ncon)) + if (!ivecaxpygez(ncon, -1, vwgt+i*ncon, pwgts+from*ncon, minpwgts+from*ncon)) continue; } @@ -1204,7 +1553,7 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (!safetos[to=mynbrs[k].pid]) continue; gain = mynbrs[k].gv + xgain; - if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon)) + if (gain >= 0 && ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxpwgts+to*ncon)) break; } if (k < 0) @@ -1216,11 +1565,11 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, continue; gain = mynbrs[j].gv + xgain; if ((mynbrs[j].gv > mynbrs[k].gv && - ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon)) + ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxpwgts+to*ncon)) || (mynbrs[j].gv == mynbrs[k].gv && mynbrs[j].ned > mynbrs[k].ned && - ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon)) + ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxpwgts+to*ncon)) || (mynbrs[j].gv == mynbrs[k].gv && mynbrs[j].ned == mynbrs[k].ned && @@ -1250,7 +1599,7 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, for (k=myrinfo->nnbrs-1; k>=0; k--) { if (!safetos[to=mynbrs[k].pid]) continue; - if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxwgt+to*ncon) || + if (ivecaxpylez(ncon, 1, vwgt+i*ncon, pwgts+to*ncon, maxpwgts+to*ncon) || BetterBalanceKWay(ncon, vwgt+i*ncon, ubfactors, -1, pwgts+from*ncon, pijbm+from*ncon, +1, pwgts+to*ncon, pijbm+to*ncon)) @@ -1334,11 +1683,11 @@ void Greedy_McKWayVolOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter, if (ctrl->dbglvl&METIS_DBG_REFINE) { printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"." " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX, - imin(nparts*ncon, pwgts), imax(nparts*ncon, pwgts), + imin(nparts*ncon, pwgts,1), imax(nparts*ncon, pwgts,1), ComputeLoadImbalance(graph, nparts, pijbm), graph->nbnd, nmoved, graph->mincut, graph->minvol); if (ctrl->minconn) - printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads), isum(nparts, nads,1)); + printf(", Doms: [%3"PRIDX" %4"PRIDX"]", imax(nparts, nads,1), isum(nparts, nads,1)); printf("\n"); } @@ -1850,3 +2199,350 @@ void KWayVolUpdate(ctrl_t *ctrl, graph_t *graph, idx_t v, idx_t from, } } + +/*************************************************************************/ +/*! K-way partitioning optimization in which the vertices are visited in + decreasing ed/sqrt(nnbrs)-id order. Note this is just an + approximation, as the ed is often split across different subdomains + and the sqrt(nnbrs) is just a crude approximation. + + \param graph is the graph that is being refined. + \param niter is the number of refinement iterations. + \param ffactor is the \em fudge-factor for allowing positive gain moves + to violate the max-pwgt constraint. + \param omode is the type of optimization that will performed among + OMODE_REFINE and OMODE_BALANCE + + +*/ +/**************************************************************************/ +void Greedy_KWayEdgeStats(ctrl_t *ctrl, graph_t *graph) +{ + /* Common variables to all types of kway-refinement/balancing routines */ + idx_t i, ii, iii, j, k, l, nvtxs, nparts, gain, u, v, uw, vw; + idx_t *xadj, *adjncy, *adjwgt, *vwgt; + idx_t *where, *pwgts, *bndptr, *bndind, *minpwgts, *maxpwgts; + idx_t nbnd; + ckrinfo_t *urinfo, *vrinfo; + cnbr_t *unbrs, *vnbrs; + real_t *tpwgts, ubfactor; + + WCOREPUSH; + + /* Link the graph fields */ + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + vwgt = graph->vwgt; + adjwgt = graph->adjwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + nparts = ctrl->nparts; + tpwgts = ctrl->tpwgts; + + /* Setup the weight intervals of the various subdomains */ + minpwgts = iwspacemalloc(ctrl, nparts+2); + maxpwgts = iwspacemalloc(ctrl, nparts+2); + + ubfactor = ctrl->ubfactors[0]; + for (i=0; i<nparts; i++) { + maxpwgts[i] = tpwgts[i]*graph->tvwgt[0]*ubfactor; + minpwgts[i] = tpwgts[i]*graph->tvwgt[0]*(0.95/ubfactor); + } + maxpwgts[nparts] = maxpwgts[nparts+1] = 0; + minpwgts[nparts] = minpwgts[nparts+1] = 0; + + /* go and determine the positive gain valid swaps */ + nbnd = graph->nbnd; + + for (ii=0; ii<nbnd; ii++) { + u = bndind[ii]; + uw = where[u]; + + urinfo = graph->ckrinfo+u; + unbrs = ctrl->cnbrpool + urinfo->inbr; + + for (j=xadj[u]; j<xadj[u+1]; j++) { + v = adjncy[j]; + vw = where[v]; + + vrinfo = graph->ckrinfo+v; + vnbrs = ctrl->cnbrpool + vrinfo->inbr; + + if (uw == vw) + continue; + if (pwgts[uw] - vwgt[u] + vwgt[v] > maxpwgts[uw] || + pwgts[vw] - vwgt[v] + vwgt[u] > maxpwgts[vw]) + continue; + + for (k=urinfo->nnbrs-1; k>=0; k--) { + if (unbrs[k].pid == vw) + break; + } + if (k < 0) + printf("Something went wrong!\n"); + gain = unbrs[k].ed-urinfo->id; + + for (k=vrinfo->nnbrs-1; k>=0; k--) { + if (vnbrs[k].pid == uw) + break; + } + if (k < 0) + printf("Something went wrong!\n"); + gain += vnbrs[k].ed-vrinfo->id; + + gain -= 2*adjwgt[j]; + + if (gain > 0) + printf(" Gain: %"PRIDX" for moving (%"PRIDX", %"PRIDX") between (%"PRIDX", %"PRIDX")\n", + gain, u, v, uw, vw); + } + } + + WCOREPOP; +} + + +/*************************************************************************/ +/*! K-way partitioning optimization in which the vertices are visited in + random order and the best edge is selected to swap its incident vertices + + \param graph is the graph that is being refined. + \param niter is the number of refinement iterations. + +*/ +/**************************************************************************/ +void Greedy_KWayEdgeCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter) +{ + /* Common variables to all types of kway-refinement/balancing routines */ + idx_t ii, j, k, pass, nvtxs, nparts, u, v, uw, vw, gain, bestgain, jbest; + idx_t from, me, to, oldcut, nmoved; + idx_t *xadj, *adjncy, *adjwgt, *vwgt; + idx_t *where, *pwgts, *perm, *bndptr, *bndind, *minpwgts, *maxpwgts; + idx_t bndtype = BNDTYPE_REFINE; + real_t *tpwgts, ubfactor; + + /* Edgecut-specific/different variables */ + idx_t nbnd, oldnnbrs; + ckrinfo_t *myrinfo, *urinfo, *vrinfo; + cnbr_t *unbrs, *vnbrs; + + WCOREPUSH; + + /* Link the graph fields */ + nvtxs = graph->nvtxs; + xadj = graph->xadj; + adjncy = graph->adjncy; + adjwgt = graph->adjwgt; + vwgt = graph->vwgt; + + bndind = graph->bndind; + bndptr = graph->bndptr; + + where = graph->where; + pwgts = graph->pwgts; + + nparts = ctrl->nparts; + tpwgts = ctrl->tpwgts; + + /* Setup the weight intervals of the various subdomains */ + minpwgts = iwspacemalloc(ctrl, nparts+2); + maxpwgts = iwspacemalloc(ctrl, nparts+2); + + ubfactor = gk_max(ctrl->ubfactors[0], ComputeLoadImbalance(graph, nparts, ctrl->pijbm)); + for (k=0; k<nparts; k++) { + maxpwgts[k] = tpwgts[k]*graph->tvwgt[0]*ubfactor; + minpwgts[k] = tpwgts[k]*graph->tvwgt[0]*(1.0/ubfactor); + } + maxpwgts[nparts] = maxpwgts[nparts+1] = 0; + minpwgts[nparts] = minpwgts[nparts+1] = 0; + + perm = iwspacemalloc(ctrl, nvtxs); + + + if (ctrl->dbglvl&METIS_DBG_REFINE) { + printf("GRE: [%6"PRIDX" %6"PRIDX"]-[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL"," + " Nv-Nb[%6"PRIDX" %6"PRIDX"], Cut: %6"PRIDX"\n", + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), minpwgts[0], maxpwgts[0], + ComputeLoadImbalance(graph, nparts, ctrl->pijbm), + graph->nvtxs, graph->nbnd, graph->mincut); + } + + + /*===================================================================== + * The top-level refinement loop + *======================================================================*/ + for (pass=0; pass<niter; pass++) { + GKASSERT(ComputeCut(graph, where) == graph->mincut); + + oldcut = graph->mincut; + nbnd = graph->nbnd; + nmoved = 0; + + /* Insert the boundary vertices in the priority queue */ + /* Visit the vertices in random order and see if you can swap them */ + irandArrayPermute(nvtxs, perm, nbnd, 1); + for (ii=0; ii<nvtxs; ii++) { + if (bndptr[u=perm[ii]] == -1) + continue; + + uw = where[u]; + + urinfo = graph->ckrinfo+u; + unbrs = ctrl->cnbrpool + urinfo->inbr; + + bestgain = 0; + jbest = -1; + for (j=xadj[u]; j<xadj[u+1]; j++) { + v = adjncy[j]; + vw = where[v]; + + if (uw == vw) + continue; + if (pwgts[uw] - vwgt[u] + vwgt[v] > maxpwgts[uw] || + pwgts[vw] - vwgt[v] + vwgt[u] > maxpwgts[vw]) + continue; + if (pwgts[uw] - vwgt[u] + vwgt[v] < minpwgts[uw] || + pwgts[vw] - vwgt[v] + vwgt[u] < minpwgts[vw]) + continue; + + vrinfo = graph->ckrinfo+v; + vnbrs = ctrl->cnbrpool + vrinfo->inbr; + + gain = -2*adjwgt[j]; + + for (k=urinfo->nnbrs-1; k>=0; k--) { + if (unbrs[k].pid == vw) + break; + } + GKASSERT(k>=0); + gain += unbrs[k].ed-urinfo->id; + + for (k=vrinfo->nnbrs-1; k>=0; k--) { + if (vnbrs[k].pid == uw) + break; + } + GKASSERT(k>=0); + gain += vnbrs[k].ed-vrinfo->id; + + if (gain > bestgain && vnbrs[k].ed > adjwgt[j]) { + bestgain = gain; + jbest = j; + } + } + + if (jbest == -1) + continue; /* no valid positive swap */ + + + /*===================================================================== + * If we got here, we can now swap the vertices + *======================================================================*/ + v = adjncy[jbest]; + vw = where[v]; + + vrinfo = graph->ckrinfo+v; + vnbrs = ctrl->cnbrpool + vrinfo->inbr; + + /* move u to v's partition */ + for (k=urinfo->nnbrs-1; k>=0; k--) { + if (unbrs[k].pid == vw) + break; + } + GKASSERT(k>=0); + + from = uw; + to = vw; + + graph->mincut -= unbrs[k].ed-urinfo->id; + nmoved++; + + IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO, + printf("\t\tMoving %6"PRIDX" from %3"PRIDX" to %3"PRIDX" [%6"PRIDX" %6"PRIDX"]. Gain: %4"PRIDX". Cut: %6"PRIDX"\n", + u, from, to, pwgts[from], pwgts[to], unbrs[k].ed-urinfo->id, graph->mincut)); + + /* Update ID/ED and BND related information for the moved vertex */ + INC_DEC(pwgts[to], pwgts[from], vwgt[u]); + UpdateMovedVertexInfoAndBND(u, from, k, to, urinfo, unbrs, where, nbnd, + bndptr, bndind, bndtype); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[u]; j<xadj[u+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + myrinfo = graph->ckrinfo+ii; + + oldnnbrs = myrinfo->nnbrs; + + UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me, + from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, bndtype); + + ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]); + } + + /* move v to u's partition */ + for (k=vrinfo->nnbrs-1; k>=0; k--) { + if (vnbrs[k].pid == uw) + break; + } + GKASSERT(k>=0); +#ifdef XXX + if (k < 0) { /* that was removed, go and re-insert it */ + k = vrinfo->nnbrs++; + vnbrs[k].pid = uw; + vnbrs[k].ed = 0; + } +#endif + + from = vw; + to = uw; + + graph->mincut -= vnbrs[k].ed-vrinfo->id; + nmoved++; + + IFSET(ctrl->dbglvl, METIS_DBG_MOVEINFO, + printf("\t\tMoving %6"PRIDX" from %3"PRIDX" to %3"PRIDX" [%6"PRIDX" %6"PRIDX"]. Gain: %4"PRIDX". Cut: %6"PRIDX"\n", + v, from, to, pwgts[from], pwgts[to], vnbrs[k].ed-vrinfo->id, graph->mincut)); + + /* Update ID/ED and BND related information for the moved vertex */ + INC_DEC(pwgts[to], pwgts[from], vwgt[v]); + UpdateMovedVertexInfoAndBND(v, from, k, to, vrinfo, vnbrs, where, nbnd, + bndptr, bndind, bndtype); + + /* Update the degrees of adjacent vertices */ + for (j=xadj[v]; j<xadj[v+1]; j++) { + ii = adjncy[j]; + me = where[ii]; + myrinfo = graph->ckrinfo+ii; + + oldnnbrs = myrinfo->nnbrs; + + UpdateAdjacentVertexInfoAndBND(ctrl, ii, xadj[ii+1]-xadj[ii], me, + from, to, myrinfo, adjwgt[j], nbnd, bndptr, bndind, bndtype); + + ASSERT(myrinfo->nnbrs <= xadj[ii+1]-xadj[ii]); + } + } + + graph->nbnd = nbnd; + + if (ctrl->dbglvl&METIS_DBG_REFINE) { + printf("\t[%6"PRIDX" %6"PRIDX"], Bal: %5.3"PRREAL", Nb: %6"PRIDX"." + " Nmoves: %5"PRIDX", Cut: %6"PRIDX", Vol: %6"PRIDX"\n", + pwgts[iargmin(nparts, pwgts,1)], imax(nparts, pwgts,1), + ComputeLoadImbalance(graph, nparts, ctrl->pijbm), + graph->nbnd, nmoved, graph->mincut, ComputeVolume(graph, where)); + } + + if (nmoved == 0 || graph->mincut == oldcut) + break; + } + + WCOREPOP; +} + diff --git a/3rdParty/metis/metis-5.1.0/libmetis/kwayrefine.c b/3rdParty/metis/metis-5.1.1/libmetis/kwayrefine.c similarity index 98% rename from 3rdParty/metis/metis-5.1.0/libmetis/kwayrefine.c rename to 3rdParty/metis/metis-5.1.1/libmetis/kwayrefine.c index 0e3c6dbd2924938538b896250c2f8b87a50ffd8a..50bc65784e6d70112bfe95b31d894bb7fdde3962 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/kwayrefine.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/kwayrefine.c @@ -5,7 +5,7 @@ \date Started 7/28/1997 \author George \author Copyright 1997-2009, Regents of the University of Minnesota -\version $Id: kwayrefine.c 10737 2011-09-13 13:37:25Z karypis $ +\version $Id: kwayrefine.c 20398 2016-11-22 17:17:12Z karypis $ */ #include "metislib.h" @@ -83,6 +83,8 @@ void RefineKWay(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph) graph = graph->finer; + graph_ReadFromDisk(ctrl, graph); + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); ASSERT(graph->vwgt != NULL); @@ -318,9 +320,12 @@ void ProjectKWayPartition(ctrl_t *ctrl, graph_t *graph) idx_t *xadj, *adjncy, *adjwgt; idx_t *cmap, *where, *bndptr, *bndind, *cwhere, *htable; graph_t *cgraph; + int dropedges; WCOREPUSH; + dropedges = ctrl->dropedges; + nparts = ctrl->nparts; cgraph = graph->coarser; @@ -352,7 +357,7 @@ void ProjectKWayPartition(ctrl_t *ctrl, graph_t *graph) for (i=0; i<nvtxs; i++) { k = cmap[i]; where[i] = cwhere[k]; - cmap[i] = cgraph->ckrinfo[k].ed; /* For optimization */ + cmap[i] = (dropedges ? 1 : cgraph->ckrinfo[k].ed); /* For optimization */ } memset(graph->ckrinfo, 0, sizeof(ckrinfo_t)*nvtxs); @@ -428,7 +433,7 @@ void ProjectKWayPartition(ctrl_t *ctrl, graph_t *graph) for (i=0; i<nvtxs; i++) { k = cmap[i]; where[i] = cwhere[k]; - cmap[i] = cgraph->vkrinfo[k].ned; /* For optimization */ + cmap[i] = (dropedges ? 1 : cgraph->vkrinfo[k].ned); /* For optimization */ } memset(graph->vkrinfo, 0, sizeof(vkrinfo_t)*nvtxs); @@ -491,7 +496,7 @@ void ProjectKWayPartition(ctrl_t *ctrl, graph_t *graph) gk_errexit(SIGERR, "Unknown objtype of %d\n", ctrl->objtype); } - graph->mincut = cgraph->mincut; + graph->mincut = (dropedges ? ComputeCut(graph, where) : cgraph->mincut); icopy(nparts*graph->ncon, cgraph->pwgts, graph->pwgts); FreeGraph(&graph->coarser); diff --git a/3rdParty/metis/metis-5.1.0/libmetis/macros.h b/3rdParty/metis/metis-5.1.1/libmetis/macros.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/macros.h rename to 3rdParty/metis/metis-5.1.1/libmetis/macros.h diff --git a/3rdParty/metis/metis-5.1.0/libmetis/mcutil.c b/3rdParty/metis/metis-5.1.1/libmetis/mcutil.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/mcutil.c rename to 3rdParty/metis/metis-5.1.1/libmetis/mcutil.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/mesh.c b/3rdParty/metis/metis-5.1.1/libmetis/mesh.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/mesh.c rename to 3rdParty/metis/metis-5.1.1/libmetis/mesh.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/meshpart.c b/3rdParty/metis/metis-5.1.1/libmetis/meshpart.c similarity index 98% rename from 3rdParty/metis/metis-5.1.0/libmetis/meshpart.c rename to 3rdParty/metis/metis-5.1.1/libmetis/meshpart.c index a66d106102fa625a2580f90d34aa986a93e73780..77fd35c55f775d74f70649c8ea47ed0eff12efe1 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/meshpart.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/meshpart.c @@ -8,7 +8,7 @@ * Started 9/29/97 * George * - * $Id: meshpart.c 13931 2013-03-29 16:48:48Z karypis $ + * $Id: meshpart.c 17513 2014-08-05 16:20:50Z dominique $ * */ @@ -237,7 +237,7 @@ void InduceRowPartFromColumnPart(idx_t nrows, idx_t *rowptr, idx_t *rowind, ASSERT(nnbrs > 0); /* assign it first to the domain with most things in common */ - rpart[i] = nbrdom[iargmax(nnbrs, nbrwgt)]; + rpart[i] = nbrdom[iargmax(nnbrs, nbrwgt,1)]; /* if overweight, assign it to the light domain */ if (pwgts[rpart[i]] > itpwgts[rpart[i]]) { diff --git a/3rdParty/metis/metis-5.1.0/libmetis/metislib.h b/3rdParty/metis/metis-5.1.1/libmetis/metislib.h similarity index 81% rename from 3rdParty/metis/metis-5.1.0/libmetis/metislib.h rename to 3rdParty/metis/metis-5.1.1/libmetis/metislib.h index 93d48f01136c0affcc1a15969b5e44701279af98..dc224f4299c53c9f0ea8167d48a6b16077b12547 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/metislib.h +++ b/3rdParty/metis/metis-5.1.1/libmetis/metislib.h @@ -22,13 +22,13 @@ #include <metis.h> -#include <rename.h> -#include <gklib_defs.h> +#include "rename.h" +#include "gklib_defs.h" -#include <defs.h> -#include <struct.h> -#include <macros.h> -#include <proto.h> +#include "defs.h" +#include "struct.h" +#include "macros.h" +#include "proto.h" #if defined(COMPILER_MSC) diff --git a/3rdParty/metis/metis-5.1.0/libmetis/minconn.c b/3rdParty/metis/metis-5.1.1/libmetis/minconn.c similarity index 99% rename from 3rdParty/metis/metis-5.1.0/libmetis/minconn.c rename to 3rdParty/metis/metis-5.1.1/libmetis/minconn.c index 86dc90fbee1ee3f832602830ded9bfbf84d82afc..9f92f2f717e8e117661b5f2415a1b9e9a07c33ee 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/minconn.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/minconn.c @@ -5,7 +5,7 @@ \date Started 7/15/98 \author George \author Copyright 1997-2009, Regents of the University of Minnesota -\version $Id: minconn.c 10513 2011-07-07 22:06:03Z karypis $ +\version $Id: minconn.c 17513 2014-08-05 16:20:50Z dominique $ */ #include "metislib.h" @@ -176,7 +176,7 @@ void UpdateEdgeSubDomainGraph(ctrl_t *ctrl, idx_t u, idx_t v, idx_t ewgt, ctrl->adwgts[u][j] = ctrl->adwgts[u][nads-1]; nads--; if (r_maxndoms != NULL && nads+1 == *r_maxndoms) - *r_maxndoms = ctrl->nads[iargmax(ctrl->nparts, ctrl->nads)]; + *r_maxndoms = ctrl->nads[iargmax(ctrl->nparts, ctrl->nads,1)]; } } ctrl->nads[u] = nads; @@ -262,12 +262,12 @@ void EliminateSubDomainEdges(ctrl_t *ctrl, graph_t *graph) while (1) { total = isum(nparts, nads, 1); avg = total/nparts; - max = nads[iargmax(nparts, nads)]; + max = nads[iargmax(nparts, nads,1)]; IFSET(ctrl->dbglvl, METIS_DBG_CONNINFO, printf("Adjacent Subdomain Stats: Total: %3"PRIDX", " "Max: %3"PRIDX"[%zu], Avg: %3"PRIDX"\n", - total, max, iargmax(nparts, nads), avg)); + total, max, iargmax(nparts, nads,1), avg)); if (max < badfactor*avg) break; diff --git a/3rdParty/metis/metis-5.1.0/libmetis/mincover.c b/3rdParty/metis/metis-5.1.1/libmetis/mincover.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/mincover.c rename to 3rdParty/metis/metis-5.1.1/libmetis/mincover.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/mmd.c b/3rdParty/metis/metis-5.1.1/libmetis/mmd.c similarity index 98% rename from 3rdParty/metis/metis-5.1.0/libmetis/mmd.c rename to 3rdParty/metis/metis-5.1.1/libmetis/mmd.c index 778cc1548beeed499a95a8b4819e65dca2bc0dc4..be6d593518359b05e58cbe40849d20fdb842b0fb 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/mmd.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/mmd.c @@ -16,7 +16,7 @@ * The meaning of invperm, and perm vectors is different from that * in genqmd_ of SparsPak * - * $Id: mmd.c 5993 2009-01-07 02:09:57Z karypis $ + * $Id: mmd.c 22385 2019-06-03 22:08:48Z karypis $ */ #include "metislib.h" @@ -316,7 +316,11 @@ idx_t mmdint(idx_t neqns, idx_t *xadj, idx_t *adjncy, idx_t *head, idx_t *forwa /* initialize the degree doubly linked lists. */ for ( node = 1; node <= neqns; node++ ) { - ndeg = xadj[node+1] - xadj[node]/* + 1*/; /* george */ + // The following is something that Olaf Schenk identified as potentially a + // bug that I introduced in the original code. For now, I reverted back + // to the original code until I have some time to check. + // ndeg = xadj[node+1] - xadj[node]/* + 1*/; /* george */ + ndeg = xadj[node+1] - xadj[node] + 1; if (ndeg == 0) ndeg = 1; fnode = head[ndeg]; diff --git a/3rdParty/metis/metis-5.1.0/libmetis/ometis.c b/3rdParty/metis/metis-5.1.1/libmetis/ometis.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/ometis.c rename to 3rdParty/metis/metis-5.1.1/libmetis/ometis.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/options.c b/3rdParty/metis/metis-5.1.1/libmetis/options.c similarity index 93% rename from 3rdParty/metis/metis-5.1.0/libmetis/options.c rename to 3rdParty/metis/metis-5.1.1/libmetis/options.c index 3bc1ac93c042131028db0fd0e456c04a49f7915b..0ca0bd2ae2a0aba4de8154f51eb7da5789c42b7c 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/options.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/options.c @@ -5,7 +5,7 @@ \date Started 5/12/2011 \author George \author Copyright 1997-2011, Regents of the University of Minnesota - \version\verbatim $Id: options.c 13901 2013-03-24 16:17:03Z karypis $ \endverbatim + \version\verbatim $Id: options.c 17717 2014-10-03 19:09:31Z dominique $ \endverbatim */ #include "metislib.h" @@ -24,6 +24,8 @@ ctrl_t *SetupCtrl(moptype_et optype, idx_t *options, idx_t ncon, idx_t nparts, memset((void *)ctrl, 0, sizeof(ctrl_t)); + ctrl->pid = getpid(); + switch (optype) { case METIS_OP_PMETIS: ctrl->objtype = GETOPTION(options, METIS_OPTION_OBJTYPE, METIS_OBJTYPE_CUT); @@ -47,8 +49,9 @@ ctrl_t *SetupCtrl(moptype_et optype, idx_t *options, idx_t ncon, idx_t nparts, case METIS_OP_KMETIS: ctrl->objtype = GETOPTION(options, METIS_OPTION_OBJTYPE, METIS_OBJTYPE_CUT); - ctrl->iptype = METIS_IPTYPE_METISRB; + ctrl->iptype = GETOPTION(options, METIS_OPTION_IPTYPE, METIS_IPTYPE_METISRB); ctrl->rtype = METIS_RTYPE_GREEDY; + ctrl->nIparts = GETOPTION(options, METIS_OPTION_NIPARTS, -1); ctrl->ncuts = GETOPTION(options, METIS_OPTION_NCUTS, 1); ctrl->niter = GETOPTION(options, METIS_OPTION_NITER, 10); ctrl->ufactor = GETOPTION(options, METIS_OPTION_UFACTOR, KMETIS_DEFAULT_UFACTOR); @@ -76,11 +79,13 @@ ctrl_t *SetupCtrl(moptype_et optype, idx_t *options, idx_t ncon, idx_t nparts, } /* common options */ - ctrl->ctype = GETOPTION(options, METIS_OPTION_CTYPE, METIS_CTYPE_SHEM); - ctrl->no2hop = GETOPTION(options, METIS_OPTION_NO2HOP, 0); - ctrl->seed = GETOPTION(options, METIS_OPTION_SEED, -1); - ctrl->dbglvl = GETOPTION(options, METIS_OPTION_DBGLVL, 0); - ctrl->numflag = GETOPTION(options, METIS_OPTION_NUMBERING, 0); + ctrl->ctype = GETOPTION(options, METIS_OPTION_CTYPE, METIS_CTYPE_SHEM); + ctrl->no2hop = GETOPTION(options, METIS_OPTION_NO2HOP, 0); + ctrl->ondisk = GETOPTION(options, METIS_OPTION_ONDISK, 0); + ctrl->seed = GETOPTION(options, METIS_OPTION_SEED, -1); + ctrl->dbglvl = GETOPTION(options, METIS_OPTION_DBGLVL, 0); + ctrl->numflag = GETOPTION(options, METIS_OPTION_NUMBERING, 0); + ctrl->dropedges = GETOPTION(options, METIS_OPTION_DROPEDGES, 0); /* set non-option information */ ctrl->optype = optype; @@ -90,7 +95,7 @@ ctrl_t *SetupCtrl(moptype_et optype, idx_t *options, idx_t ncon, idx_t nparts, /* setup the target partition weights */ if (ctrl->optype != METIS_OP_OMETIS) { - ctrl->tpwgts = rmalloc(nparts*ncon, "SetupCtrl: ctrl->tpwgts"); + ctrl->tpwgts = rsmalloc((nparts+2)*ncon, 0.0, "SetupCtrl: ctrl->tpwgts"); if (tpwgts) { rcopy(nparts*ncon, tpwgts, ctrl->tpwgts); } @@ -237,10 +242,14 @@ void PrintCtrl(ctrl_t *ctrl) printf("Unknown!\n"); } - printf(" Perform a 2-hop matching: %s\n", (ctrl->no2hop ? "Yes" : "No")); + printf(" Perform a 2-hop matching: %s\n", (ctrl->no2hop ? "No" : "Yes")); + + printf(" On disk storage: %s\n", (ctrl->ondisk ? "Yes" : "No")); + printf(" Drop edges: %s\n", (ctrl->dropedges ? "Yes" : "No")); printf(" Number of balancing constraints: %"PRIDX"\n", ctrl->ncon); printf(" Number of refinement iterations: %"PRIDX"\n", ctrl->niter); + printf(" Number of initial partitionings: %"PRIDX"\n", ctrl->nIparts); printf(" Random number seed: %"PRIDX"\n", ctrl->seed); if (ctrl->optype == METIS_OP_OMETIS) { @@ -256,7 +265,7 @@ void PrintCtrl(ctrl_t *ctrl) if (ctrl->optype == METIS_OP_KMETIS) { printf(" Minimize connectivity: %s\n", (ctrl->minconn ? "Yes" : "No")); - printf(" Create contigous partitions: %s\n", (ctrl->contig ? "Yes" : "No")); + printf(" Create contiguous partitions: %s\n", (ctrl->contig ? "Yes" : "No")); } modnum = (ctrl->ncon==1 ? 5 : (ctrl->ncon==2 ? 3 : (ctrl->ncon==3 ? 2 : 1))); @@ -370,7 +379,7 @@ int CheckParams(ctrl_t *ctrl) IFSET(dbglvl, METIS_DBG_INFO, printf("Input Error: Incorrect coarsening scheme.\n")); return 0; } - if (ctrl->iptype != METIS_IPTYPE_METISRB) { + if (ctrl->iptype != METIS_IPTYPE_METISRB && ctrl->iptype != METIS_IPTYPE_GROW) { IFSET(dbglvl, METIS_DBG_INFO, printf("Input Error: Incorrect initial partitioning scheme.\n")); return 0; } diff --git a/3rdParty/metis/metis-5.1.0/libmetis/parmetis.c b/3rdParty/metis/metis-5.1.1/libmetis/parmetis.c similarity index 87% rename from 3rdParty/metis/metis-5.1.0/libmetis/parmetis.c rename to 3rdParty/metis/metis-5.1.1/libmetis/parmetis.c index 631d811bc3f85f95498c5a86b02700ed9f99f75d..984509a77fdf2c51c700a45f55de5a1b7c21ed76 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/parmetis.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/parmetis.c @@ -156,7 +156,8 @@ void MlevelNestedDissectionP(ctrl_t *ctrl, graph_t *graph, idx_t *order, /*************************************************************************/ -/*! This function bisects a graph by computing a vertex separator */ +/*! This function bisects a graph by computing a vertex separator +*/ /**************************************************************************/ int METIS_ComputeVertexSeparator(idx_t *nvtxs, idx_t *xadj, idx_t *adjncy, idx_t *vwgt, idx_t *options, idx_t *r_sepsize, idx_t *part) @@ -721,3 +722,96 @@ void FM_2WayNodeRefine2SidedP(ctrl_t *ctrl, graph_t *graph, WCOREPOP; } + +/*************************************************************************/ +/*! This function computes a cache-friendly permutation of each partition. + The resulting permutation is retuned in old2new, which is a vector of + size nvtxs such for vertex i, old2new[i] is its new vertex number. +*/ +/**************************************************************************/ +int METIS_CacheFriendlyReordering(idx_t nvtxs, idx_t *xadj, idx_t *adjncy, + idx_t *part, idx_t *old2new) +{ + idx_t i, j, k, first, last, lastlevel, maxdegree, nparts; + idx_t *cot, *pos, *pwgts; + ikv_t *levels; + + InitRandom(123); + + /* This array ([C]losed[O]pen[T]odo => cot) serves three purposes. + Positions from [0...first) is the current iperm[] vector of the explored vertices; + Positions from [first...last) is the OPEN list (i.e., visited vertices); + Positions from [last...nvtxs) is the todo list. */ + cot = iincset(nvtxs, 0, imalloc(nvtxs, "METIS_CacheFriendlyReordering: cor")); + + /* This array will function like pos + touched of the CC method */ + pos = iincset(nvtxs, 0, imalloc(nvtxs, "METIS_CacheFriendlyReordering: pos")); + + /* pick a random starting vertex */ + i = irandInRange(nvtxs); + pos[0] = cot[0] = i; + pos[i] = cot[i] = 0; + + /* compute a BFS ordering */ + first = last = 0; + lastlevel = 0; + maxdegree = 0; + while (first < nvtxs) { + if (first == last) { /* Find another starting vertex */ + k = cot[last]; + ASSERT(pos[k] >= 0); + pos[k] = --lastlevel; /* mark node as being visited by assigning its current level (-ve) */ + last++; + } + + i = cot[first++]; + maxdegree = (maxdegree < xadj[i+1]-xadj[i] ? xadj[i+1]-xadj[i] : maxdegree); + for (j=xadj[i]; j<xadj[i+1]; j++) { + k = adjncy[j]; + /* if a node has been already been visited, its pos[] will be -1 */ + if (pos[k] >= 0) { + /* pos[k] is the location within cot of where k resides (it is in the 'todo' part); + put in that location cot[last] that we are about to overwrite + and update pos[cot[last]] to reflect that. */ + cot[pos[k]] = cot[last]; + pos[cot[last]] = pos[k]; + + cot[last++] = k; /* put node at the end of the "queue" */ + pos[k] = pos[i]-1; /* mark node as being visited by assigning to next level */ + lastlevel = pos[k]; /* for correctly advancing the levels in case of disconnected graphs */ + } + } + } +// printf("lastlevel: %d\n", (int)-lastlevel); + + /* sort based on decreasing level and decreasing degree (RCM) */ + levels = ikvmalloc(nvtxs, "METIS_CacheFriendlyReordering: levels"); + maxdegree++; + for (i=0; i<nvtxs; i++) { + levels[i].val = i; + levels[i].key = -pos[i]*maxdegree + xadj[i+1]-xadj[i]; + } + ikvsortd(nvtxs, levels); + + /* figure out the partitions */ + nparts = imax(nvtxs, part, 1)+1; + pwgts = ismalloc(nparts+1, 0, "METIS_CacheFriendlyReordering: pwgts"); + + for (i=0; i<nvtxs; i++) + pwgts[part[i]]++; + MAKECSR(i, nparts, pwgts); + + for (i=0; i<nvtxs; i++) + old2new[levels[i].val] = pwgts[part[levels[i].val]]++; + +#ifdef XXX + for (i=0; i<nvtxs; i++) + for (j=xadj[i]; j<xadj[i+1]; j++) + printf("COO: %d %d\n", (int)old2new[i], (int)old2new[adjncy[j]]); +#endif + + gk_free((void **)&cot, &pos, &levels, &pwgts, LTERM); + + return METIS_OK; +} + diff --git a/3rdParty/metis/metis-5.1.0/libmetis/pmetis.c b/3rdParty/metis/metis-5.1.1/libmetis/pmetis.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/pmetis.c rename to 3rdParty/metis/metis-5.1.1/libmetis/pmetis.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/proto.h b/3rdParty/metis/metis-5.1.1/libmetis/proto.h similarity index 95% rename from 3rdParty/metis/metis-5.1.0/libmetis/proto.h rename to 3rdParty/metis/metis-5.1.1/libmetis/proto.h index f852ff59e33feecc6a9c9bb3e5c4a5f2768e3c82..3a8bd80d5c7a8a80bd8c6240064475947d9a81ca 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/proto.h +++ b/3rdParty/metis/metis-5.1.1/libmetis/proto.h @@ -8,7 +8,7 @@ * Started 10/19/95 * George * - * $Id: proto.h 13933 2013-03-29 22:20:46Z karypis $ + * $Id: proto.h 20398 2016-11-22 17:17:12Z karypis $ * */ @@ -47,6 +47,7 @@ idx_t Match_2HopAny(ctrl_t *ctrl, graph_t *graph, idx_t *perm, idx_t *match, idx_t cnvtxs, size_t *r_nunmatched, size_t maxdegree); idx_t Match_2HopAll(ctrl_t *ctrl, graph_t *graph, idx_t *perm, idx_t *match, idx_t cnvtxs, size_t *r_nunmatched, size_t maxdegree); +idx_t Match_JC(ctrl_t *ctrl, graph_t *graph); void PrintCGraphStats(ctrl_t *ctrl, graph_t *graph); void CreateCoarseGraph(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, idx_t *match); @@ -54,7 +55,7 @@ void CreateCoarseGraphNoMask(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, idx_t *match); void CreateCoarseGraphPerm(ctrl_t *ctrl, graph_t *graph, idx_t cnvtxs, idx_t *match, idx_t *perm); -graph_t *SetupCoarseGraph(graph_t *graph, idx_t cnvtxs, idx_t dovsize); +graph_t *SetupCoarseGraph(graph_t *graph, idx_t cnvtxs, int dovsize); void ReAdjustMemory(ctrl_t *ctrl, graph_t *graph, graph_t *cgraph); @@ -126,6 +127,8 @@ graph_t *CreateGraph(void); void InitGraph(graph_t *graph); void FreeRData(graph_t *graph); void FreeGraph(graph_t **graph); +void graph_WriteToDisk(ctrl_t *ctrl, graph_t *graph); +void graph_ReadFromDisk(ctrl_t *ctrl, graph_t *graph); /* initpart.c */ @@ -142,6 +145,10 @@ void GrowBisectionNode2(ctrl_t *ctrl, graph_t *graph, real_t *ntpwgts, idx_t nip /* kmetis.c */ idx_t MlevelKWayPartitioning(ctrl_t *ctrl, graph_t *graph, idx_t *part); void InitKWayPartitioning(ctrl_t *ctrl, graph_t *graph); +idx_t BlockKWayPartitioning(ctrl_t *ctrl, graph_t *graph, idx_t *part); +idx_t GrowMultisection(ctrl_t *ctrl, graph_t *graph, idx_t nparts, idx_t *where); +void BalanceAndRefineLP(ctrl_t *ctrl, graph_t *graph, idx_t nparts, idx_t *where); +void BalanceAndRefine(ctrl_t *ctrl, graph_t *graph, idx_t nparts, idx_t *where); /* kwayfm.c */ @@ -161,6 +168,8 @@ void KWayVolUpdate(ctrl_t *ctrl, graph_t *graph, idx_t v, idx_t from, idx_t to, ipq_t *queue, idx_t *vstatus, idx_t *r_nupd, idx_t *updptr, idx_t *updind, idx_t bndtype, idx_t *vmarker, idx_t *pmarker, idx_t *modind); +void Greedy_KWayEdgeStats(ctrl_t *ctrl, graph_t *graph); +void Greedy_KWayEdgeCutOptimize(ctrl_t *ctrl, graph_t *graph, idx_t niter); /* kwayrefine.c */ diff --git a/3rdParty/metis/metis-5.1.0/libmetis/refine.c b/3rdParty/metis/metis-5.1.1/libmetis/refine.c similarity index 95% rename from 3rdParty/metis/metis-5.1.0/libmetis/refine.c rename to 3rdParty/metis/metis-5.1.1/libmetis/refine.c index c08dc2ddb092cec4ed780427ae935217734809a1..9a9fc0e3ca83a5d24f42030429cbc8ddb3b27009 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/refine.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/refine.c @@ -5,7 +5,7 @@ \date Started 7/24/1997 \author George \author Copyright 1997-2009, Regents of the University of Minnesota -\version\verbatim $Id: refine.c 10513 2011-07-07 22:06:03Z karypis $ \endverbatim +\version\verbatim $Id: refine.c 14362 2013-05-21 21:35:23Z karypis $ \endverbatim */ #include "metislib.h" @@ -37,6 +37,8 @@ void Refine2Way(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph, real_t *tpwgts) break; graph = graph->finer; + graph_ReadFromDisk(ctrl, graph); + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); Project2WayPartition(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr)); @@ -146,9 +148,12 @@ void Project2WayPartition(ctrl_t *ctrl, graph_t *graph) idx_t *cwhere, *cbndptr; idx_t *id, *ed; graph_t *cgraph; + int dropedges; Allocate2WayPartitionMemory(ctrl, graph); + dropedges = ctrl->dropedges; + cgraph = graph->coarser; cwhere = cgraph->where; cbndptr = cgraph->bndptr; @@ -171,7 +176,7 @@ void Project2WayPartition(ctrl_t *ctrl, graph_t *graph) for (i=0; i<nvtxs; i++) { j = cmap[i]; where[i] = cwhere[j]; - cmap[i] = cbndptr[j]; + cmap[i] = (dropedges ? 0 : cbndptr[j]); } /* Compute the refinement information of the nodes */ @@ -199,7 +204,7 @@ void Project2WayPartition(ctrl_t *ctrl, graph_t *graph) if (ted > 0 || istart == iend) BNDInsert(nbnd, bndind, bndptr, i); } - graph->mincut = cgraph->mincut; + graph->mincut = (dropedges ? ComputeCut(graph, where) : cgraph->mincut); graph->nbnd = nbnd; /* copy pwgts */ diff --git a/3rdParty/metis/metis-5.1.0/libmetis/rename.h b/3rdParty/metis/metis-5.1.1/libmetis/rename.h similarity index 97% rename from 3rdParty/metis/metis-5.1.0/libmetis/rename.h rename to 3rdParty/metis/metis-5.1.1/libmetis/rename.h index 62b03b491b93ff98dc0ab38f0fa9c80a4791ed65..59a5e762b843cfb41a5a9fb6f06390ed8c7140e3 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/rename.h +++ b/3rdParty/metis/metis-5.1.1/libmetis/rename.h @@ -8,7 +8,7 @@ * Started 10/2/97 * George * - * $Id: rename.h 13933 2013-03-29 22:20:46Z karypis $ + * $Id: rename.h 20398 2016-11-22 17:17:12Z karypis $ * */ @@ -38,6 +38,7 @@ #define Match_2Hop libmetis__Match_2Hop #define Match_2HopAny libmetis__Match_2HopAny #define Match_2HopAll libmetis__Match_2HopAll +#define Match_JC libmetis__Match_JC #define PrintCGraphStats libmetis__PrintCGraphStats #define CreateCoarseGraph libmetis__CreateCoarseGraph #define CreateCoarseGraphNoMask libmetis__CreateCoarseGraphNoMask @@ -96,6 +97,8 @@ #define InitGraph libmetis__InitGraph #define FreeRData libmetis__FreeRData #define FreeGraph libmetis__FreeGraph +#define graph_WriteToDisk libmetis__graph_WriteToDisk +#define graph_ReadFromDisk libmetis__graph_ReadFromDisk /* initpart.c */ #define Init2WayPartition libmetis__Init2WayPartition diff --git a/3rdParty/metis/metis-5.1.0/libmetis/separator.c b/3rdParty/metis/metis-5.1.1/libmetis/separator.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/separator.c rename to 3rdParty/metis/metis-5.1.1/libmetis/separator.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/sfm.c b/3rdParty/metis/metis-5.1.1/libmetis/sfm.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/sfm.c rename to 3rdParty/metis/metis-5.1.1/libmetis/sfm.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/srefine.c b/3rdParty/metis/metis-5.1.1/libmetis/srefine.c similarity index 98% rename from 3rdParty/metis/metis-5.1.0/libmetis/srefine.c rename to 3rdParty/metis/metis-5.1.1/libmetis/srefine.c index 603f782ad4e662b56f3796e29539798219478a8b..5d3560bde32a957a9a305d301c7907d43dc07b06 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/srefine.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/srefine.c @@ -8,7 +8,7 @@ * Started 8/1/97 * George * - * $Id: srefine.c 10515 2011-07-08 15:46:18Z karypis $ + * $Id: srefine.c 14362 2013-05-21 21:35:23Z karypis $ * */ @@ -32,6 +32,8 @@ void Refine2WayNode(ctrl_t *ctrl, graph_t *orggraph, graph_t *graph) do { graph = graph->finer; + graph_ReadFromDisk(ctrl, graph); + IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_startcputimer(ctrl->ProjectTmr)); Project2WayNodePartition(ctrl, graph); IFSET(ctrl->dbglvl, METIS_DBG_TIME, gk_stopcputimer(ctrl->ProjectTmr)); diff --git a/3rdParty/metis/metis-5.1.0/libmetis/stat.c b/3rdParty/metis/metis-5.1.1/libmetis/stat.c similarity index 81% rename from 3rdParty/metis/metis-5.1.0/libmetis/stat.c rename to 3rdParty/metis/metis-5.1.1/libmetis/stat.c index f19791b535681f6980170e7a47573420f8400352..6860094317cfa807fb126cf3ed9c6dfe6a8e10ea 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/stat.c +++ b/3rdParty/metis/metis-5.1.1/libmetis/stat.c @@ -8,7 +8,7 @@ * Started 7/25/97 * George * - * $Id: stat.c 9942 2011-05-17 22:09:52Z karypis $ + * $Id: stat.c 17513 2014-08-05 16:20:50Z dominique $ * */ @@ -53,8 +53,8 @@ void ComputePartitionInfoBipartite(graph_t *graph, idx_t nparts, idx_t *where) if (ncon == 1) { printf("\tBalance: %5.3"PRREAL" out of %5.3"PRREAL"\n", - 1.0*nparts*kpwgts[iargmax(nparts, kpwgts)]/(1.0*isum(nparts, kpwgts, 1)), - 1.0*nparts*vwgt[iargmax(nvtxs, vwgt)]/(1.0*isum(nparts, kpwgts, 1))); + 1.0*nparts*kpwgts[iargmax(nparts, kpwgts,1)]/(1.0*isum(nparts, kpwgts, 1)), + 1.0*nparts*vwgt[iargmax(nvtxs, vwgt,1)]/(1.0*isum(nparts, kpwgts, 1))); } else { printf("\tBalance:"); @@ -90,20 +90,20 @@ void ComputePartitionInfoBipartite(graph_t *graph, idx_t nparts, idx_t *where) for (i=0; i<nparts; i++) kpwgts[i] = isum(nparts, padjncy+i*nparts, 1); printf("Min/Max/Avg/Bal # of adjacent subdomains: %5"PRIDX" %5"PRIDX" %5"PRIDX" %7.3"PRREAL"\n", - kpwgts[iargmin(nparts, kpwgts)], kpwgts[iargmax(nparts, kpwgts)], isum(nparts, kpwgts, 1)/nparts, - 1.0*nparts*kpwgts[iargmax(nparts, kpwgts)]/(1.0*isum(nparts, kpwgts, 1))); + kpwgts[iargmin(nparts, kpwgts,1)], kpwgts[iargmax(nparts, kpwgts,1)], isum(nparts, kpwgts, 1)/nparts, + 1.0*nparts*kpwgts[iargmax(nparts, kpwgts,1)]/(1.0*isum(nparts, kpwgts, 1))); for (i=0; i<nparts; i++) kpwgts[i] = isum(nparts, padjcut+i*nparts, 1); printf("Min/Max/Avg/Bal # of adjacent subdomain cuts: %5"PRIDX" %5"PRIDX" %5"PRIDX" %7.3"PRREAL"\n", - kpwgts[iargmin(nparts, kpwgts)], kpwgts[iargmax(nparts, kpwgts)], isum(nparts, kpwgts, 1)/nparts, - 1.0*nparts*kpwgts[iargmax(nparts, kpwgts)]/(1.0*isum(nparts, kpwgts, 1))); + kpwgts[iargmin(nparts, kpwgts,1)], kpwgts[iargmax(nparts, kpwgts,1)], isum(nparts, kpwgts, 1)/nparts, + 1.0*nparts*kpwgts[iargmax(nparts, kpwgts,1)]/(1.0*isum(nparts, kpwgts, 1))); for (i=0; i<nparts; i++) kpwgts[i] = isum(nparts, padjwgt+i*nparts, 1); printf("Min/Max/Avg/Bal/Frac # of interface nodes: %5"PRIDX" %5"PRIDX" %5"PRIDX" %7.3"PRREAL" %7.3"PRREAL"\n", - kpwgts[iargmin(nparts, kpwgts)], kpwgts[iargmax(nparts, kpwgts)], isum(nparts, kpwgts, 1)/nparts, - 1.0*nparts*kpwgts[iargmax(nparts, kpwgts)]/(1.0*isum(nparts, kpwgts, 1)), 1.0*isum(nparts, kpwgts, 1)/(1.0*nvtxs)); + kpwgts[iargmin(nparts, kpwgts,1)], kpwgts[iargmax(nparts, kpwgts,1)], isum(nparts, kpwgts, 1)/nparts, + 1.0*nparts*kpwgts[iargmax(nparts, kpwgts,1)]/(1.0*isum(nparts, kpwgts, 1)), 1.0*isum(nparts, kpwgts, 1)/(1.0*nvtxs)); if (mustfree == 1 || mustfree == 3) { @@ -137,7 +137,7 @@ void ComputePartitionBalance(graph_t *graph, idx_t nparts, idx_t *where, real_t if (vwgt == NULL) { for (i=0; i<nvtxs; i++) kpwgts[where[i]]++; - ubvec[0] = 1.0*nparts*kpwgts[iargmax(nparts, kpwgts)]/(1.0*nvtxs); + ubvec[0] = 1.0*nparts*kpwgts[iargmax(nparts, kpwgts,1)]/(1.0*nvtxs); } else { for (j=0; j<ncon; j++) { @@ -145,7 +145,7 @@ void ComputePartitionBalance(graph_t *graph, idx_t nparts, idx_t *where, real_t for (i=0; i<graph->nvtxs; i++) kpwgts[where[i]] += vwgt[i*ncon+j]; - ubvec[j] = 1.0*nparts*kpwgts[iargmax(nparts, kpwgts)]/(1.0*isum(nparts, kpwgts, 1)); + ubvec[j] = 1.0*nparts*kpwgts[iargmax(nparts, kpwgts,1)]/(1.0*isum(nparts, kpwgts, 1)); } } @@ -168,7 +168,7 @@ real_t ComputeElementBalance(idx_t ne, idx_t nparts, idx_t *where) for (i=0; i<ne; i++) kpwgts[where[i]]++; - balance = 1.0*nparts*kpwgts[iargmax(nparts, kpwgts)]/(1.0*isum(nparts, kpwgts, 1)); + balance = 1.0*nparts*kpwgts[iargmax(nparts, kpwgts,1)]/(1.0*isum(nparts, kpwgts, 1)); gk_free((void **)&kpwgts, LTERM); diff --git a/3rdParty/metis/metis-5.1.0/libmetis/stdheaders.h b/3rdParty/metis/metis-5.1.1/libmetis/stdheaders.h similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/stdheaders.h rename to 3rdParty/metis/metis-5.1.1/libmetis/stdheaders.h diff --git a/3rdParty/metis/metis-5.1.0/libmetis/struct.h b/3rdParty/metis/metis-5.1.1/libmetis/struct.h similarity index 93% rename from 3rdParty/metis/metis-5.1.0/libmetis/struct.h rename to 3rdParty/metis/metis-5.1.1/libmetis/struct.h index 5fc8588df6cf25b8ddc4230f58b5c76c11e6caea..afd8c24fe8f27f13529062fe581b2c2dbf52a291 100644 --- a/3rdParty/metis/metis-5.1.0/libmetis/struct.h +++ b/3rdParty/metis/metis-5.1.1/libmetis/struct.h @@ -8,7 +8,7 @@ * Started 9/26/95 * George * - * $Id: struct.h 13900 2013-03-24 15:27:07Z karypis $ + * $Id: struct.h 14362 2013-05-21 21:35:23Z karypis $ */ #ifndef _LIBMETIS_STRUCT_H_ @@ -96,9 +96,9 @@ typedef struct graph_t { application or library memory */ int free_xadj, free_vwgt, free_vsize, free_adjncy, free_adjwgt; - idx_t *label; + idx_t *cmap; /* The contraction/coarsening map */ - idx_t *cmap; + idx_t *label; /* The labels of the vertices for recusive bisection (pmetis/ometis) */ /* Partition parameters */ idx_t mincut, minvol; @@ -116,7 +116,16 @@ typedef struct graph_t { /* Node refinement information */ nrinfo_t *nrinfo; + /* various fields for out-of-core processing */ + int gID; + int ondisk; + + /* keep track of the dropped edgewgt */ + idx_t droppedewgt; + + /* the linked-list structure of the sequence of graphs */ struct graph_t *coarser, *finer; + } graph_t; @@ -147,6 +156,7 @@ typedef struct ctrl_t { idx_t CoarsenTo; /* The # of vertices in the coarsest graph */ idx_t nIparts; /* The number of initial partitions to compute */ idx_t no2hop; /* Indicates if 2-hop matching will be used */ + idx_t ondisk; /* Indicates out-of-core execution */ idx_t minconn; /* Indicates if the subdomain connectivity will be minimized */ idx_t contig; /* Indicates if contigous partitions are required */ idx_t nseps; /* The number of separators to be found during multiple bisections */ @@ -157,6 +167,7 @@ typedef struct ctrl_t { idx_t ncuts; /* The number of different partitionings to compute */ idx_t niter; /* The number of iterations during each refinement */ idx_t numflag; /* The user-supplied numflag for the graph */ + idx_t dropedges; /* Indicates if edges will be randomly dropped during coarsening */ idx_t *maxvwgt; /* The maximum allowed weight for a vertex */ idx_t ncon; /*!< The number of balancing constraints */ @@ -199,6 +210,8 @@ typedef struct ctrl_t { idx_t **adwgts; /* The edge-weight to the adjacent domains */ idx_t *pvec1, *pvec2; /* Auxiliar nparts-size vectors for efficiency */ + /* ondisk related info */ + pid_t pid; /*!< The pid of the running process */ } ctrl_t; diff --git a/3rdParty/metis/metis-5.1.0/libmetis/timing.c b/3rdParty/metis/metis-5.1.1/libmetis/timing.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/timing.c rename to 3rdParty/metis/metis-5.1.1/libmetis/timing.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/util.c b/3rdParty/metis/metis-5.1.1/libmetis/util.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/util.c rename to 3rdParty/metis/metis-5.1.1/libmetis/util.c diff --git a/3rdParty/metis/metis-5.1.0/libmetis/wspace.c b/3rdParty/metis/metis-5.1.1/libmetis/wspace.c similarity index 100% rename from 3rdParty/metis/metis-5.1.0/libmetis/wspace.c rename to 3rdParty/metis/metis-5.1.1/libmetis/wspace.c diff --git a/CMake/cmake_config_files/BILBO.config.cmake b/CMake/cmake_config_files/BILBO.config.cmake index 3c7f0f728ddad36d22ff1d65d83aa7927c14ed48..093fe3200837a3916e8a14b16042732c2b6db218 100644 --- a/CMake/cmake_config_files/BILBO.config.cmake +++ b/CMake/cmake_config_files/BILBO.config.cmake @@ -3,11 +3,3 @@ # Responsible: Soeren Peters # OS: MacOS X ################################################################################# - -################################################################################# -# METIS -################################################################################# -SET(METIS_INCLUDEDIR "/usr/local/include") -SET(METIS_DEBUG_LIBRARY "/usr/local/lib/libmetis.a") -SET(METIS_RELEASE_LIBRARY "/usr/local/lib/libmetis.a") - diff --git a/CMake/cmake_config_files/ELLADAN.config.cmake b/CMake/cmake_config_files/ELLADAN.config.cmake index 80291455e6db49f542b847640ec187620d7eacca..ff87d1b9d8d8aac05fe72cb1e303ad7de6663e8f 100644 --- a/CMake/cmake_config_files/ELLADAN.config.cmake +++ b/CMake/cmake_config_files/ELLADAN.config.cmake @@ -5,10 +5,5 @@ ################################################################################# set(NVCUDASAMPLES_ROOT "~/cuda-samples/Common") -################################################################################# -# METIS -################################################################################# -set(METIS_INCLUDEDIR "/usr/include") -set(METIS_DEBUG_LIBRARY "/usr/lib/x86_64-linux-gnu/libmetis.so") -set(METIS_RELEASE_LIBRARY "/usr/lib/x86_64-linux-gnu/libmetis.so") + diff --git a/cpu.cmake b/cpu.cmake index 0f8c9a5ac6e3d98a29049be69390b4a1ca365c4f..fd33baa9173f9c7af7021e8c22e39069cfff82c2 100644 --- a/cpu.cmake +++ b/cpu.cmake @@ -75,6 +75,10 @@ IF(${CMAKE_SYSTEM_PROCESSOR} MATCHES "ia64") LIST(APPEND VF_COMPILER_DEFINITION _M_IA64) ENDIF() +if(${USE_METIS} AND NOT METIS_INCLUDEDIR) + add_subdirectory(${VF_THIRD_DIR}/metis/metis-5.1.1) +endif() + add_subdirectory(${VF_THIRD_DIR}/MuParser) diff --git a/src/cpu/VirtualFluidsCore/CMakeLists.txt b/src/cpu/VirtualFluidsCore/CMakeLists.txt index a051433245a3c65dc899522738016ce79260105a..f23e96006cea40e9ef7721c0de06586448a1e53e 100644 --- a/src/cpu/VirtualFluidsCore/CMakeLists.txt +++ b/src/cpu/VirtualFluidsCore/CMakeLists.txt @@ -1,7 +1,9 @@ -IF(${USE_METIS}) +IF(${USE_METIS} AND METIS_RELEASE_LIBRARY AND METIS_DEBUG_LIBRARY) SET(LINK_LIBRARY optimized ${METIS_RELEASE_LIBRARY} debug ${METIS_DEBUG_LIBRARY}) SET(CAB_ADDITIONAL_LINK_LIBRARIES ${CAB_ADDITIONAL_LINK_LIBRARIES} ${LINK_LIBRARY}) +ELSE() + SET(CAB_ADDITIONAL_LINK_LIBRARIES ${CAB_ADDITIONAL_LINK_LIBRARIES} metis) ENDIF() IF(${USE_VTK}) @@ -37,8 +39,9 @@ target_include_directories(${library_name} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Co target_include_directories(${library_name} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) -target_include_directories(${library_name} PUBLIC ${METIS_INCLUDEDIR}) - +IF(${USE_METIS} AND METIS_INCLUDEDIR) + target_include_directories(${library_name} PUBLIC ${METIS_INCLUDEDIR}) +ENDIF() IF(${USE_BOOST}) target_include_directories(${library_name} PRIVATE ${Boost_INCLUDE_DIR})