/* ========================================================================== */ /* === Source/Mongoose_Sanitize.cpp ========================================= */ /* ========================================================================== */ /* ----------------------------------------------------------------------------- * Mongoose Graph Partitioning Library, Copyright (C) 2017-2018, * Scott P. Kolodziej, Nuri S. Yeralan, Timothy A. Davis, William W. Hager * Mongoose is licensed under Version 3 of the GNU General Public License. * Mongoose is also available under other licenses; contact authors for details. * SPDX-License-Identifier: GPL-3.0-only * -------------------------------------------------------------------------- */ #include "Mongoose_Sanitize.hpp" #include "Mongoose_Internal.hpp" using namespace std; namespace Mongoose { cs *sanitizeMatrix(cs *compressed_A, bool symmetricTriangular, bool makeEdgeWeightsBinary) { cs *cleanMatrix; if (symmetricTriangular) { cleanMatrix = mirrorTriangular(compressed_A); } else { cs *A_transpose = cs_transpose(compressed_A, 1); if (!A_transpose) { return NULL; } cleanMatrix = cs_add(compressed_A, A_transpose, 0.5, 0.5); cs_spfree(A_transpose); } if (!cleanMatrix) { return NULL; } removeDiagonal(cleanMatrix); cs *cleanMatrix_transpose = cs_transpose(cleanMatrix, 1); cs_spfree(cleanMatrix); if (!cleanMatrix_transpose) { return NULL; } cleanMatrix = cs_transpose(cleanMatrix_transpose, 1); cs_spfree(cleanMatrix_transpose); if (!cleanMatrix) { return NULL; } if (cleanMatrix->x) { for (Int p = 0; p < cleanMatrix->p[cleanMatrix->n]; p++) { if (makeEdgeWeightsBinary) { // Make edge weights binary if (cleanMatrix->x[p] != 0) { cleanMatrix->x[p] = 1; } } else { // Force edge weights to be positive cleanMatrix->x[p] = fabs(cleanMatrix->x[p]); } } } return cleanMatrix; } void removeDiagonal(cs *A) { Int n = A->n; Int *Ap = A->p; Int *Ai = A->i; double *Ax = A->x; Int nz = 0; Int old_Ap = Ap[0]; for (Int j = 0; j < n; j++) { for (Int p = old_Ap; p < Ap[j + 1]; p++) { if (Ai[p] != j) { Ai[nz] = Ai[p]; if (Ax) Ax[nz] = Ax[p]; nz++; } } old_Ap = Ap[j + 1]; Ap[j + 1] = nz; } } // Requires A to be a triangular matrix with no diagonal. cs *mirrorTriangular(cs *A) { if (!A) return NULL; Int A_n = A->n; Int A_nz = A->p[A_n]; Int B_nz = 2 * A_nz; bool values = (A->x != NULL); // allocate B in triplet form, with values Bx if A has values cs *B = cs_spalloc(A_n, A_n, B_nz, values, 1); if (!B) return NULL; Int *Ap = A->p; Int *Ai = A->i; double *Ax = A->x; Int *Bj = B->p; Int *Bi = B->i; double *Bx = B->x; Int nz = 0; for (Int j = 0; j < A_n; j++) { for (Int p = Ap[j]; p < Ap[j + 1]; p++) { Bi[nz] = Ai[p]; Bj[nz] = j; if (values) Bx[nz] = Ax[p]; nz++; Bi[nz] = j; Bj[nz] = Ai[p]; if (values) Bx[nz] = Ax[p]; nz++; } } B->nz = nz; cs *C = cs_compress(B); cs_spfree(B); return C; } } // end namespace Mongoose