static char help[] = "Tests MatInvertVariableBlockEnvelope()\n\n"; #include extern PetscErrorCode MatIsDiagonal(Mat); extern PetscErrorCode BuildMatrix(const PetscInt *, PetscInt, const PetscInt *, Mat *); int main(int argc, char **argv) { Mat A, C, D, F; PetscInt i, j, rows[2], *parts, cnt, N = 21, nblocks, *blocksizes; PetscScalar values[2][2]; PetscReal rand; PetscRandom rctx; PetscMPIInt size; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &argv, NULL, help)); PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_DENSE)); PetscCall(MatCreate(PETSC_COMM_WORLD, &C)); PetscCall(MatSetSizes(C, PETSC_DECIDE, PETSC_DECIDE, 6, 18)); PetscCall(MatSetFromOptions(C)); PetscCall(MatSetUp(C)); values[0][0] = 2; values[0][1] = 1; values[1][0] = 1; values[1][1] = 2; for (i = 0; i < 3; i++) { rows[0] = 2 * i; rows[1] = 2 * i + 1; PetscCall(MatSetValues(C, 2, rows, 2, rows, (PetscScalar *)values, INSERT_VALUES)); } PetscCall(MatAssemblyBegin(C, MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(C, MAT_FINAL_ASSEMBLY)); PetscCall(MatView(C, PETSC_VIEWER_STDOUT_WORLD)); PetscCall(MatMatTransposeMult(C, C, MAT_INITIAL_MATRIX, PETSC_DETERMINE, &A)); PetscCall(MatView(A, PETSC_VIEWER_STDOUT_WORLD)); PetscCall(MatInvertVariableBlockEnvelope(A, MAT_INITIAL_MATRIX, &D)); PetscCall(MatView(D, PETSC_VIEWER_STDOUT_WORLD)); PetscCall(MatMatMult(A, D, MAT_INITIAL_MATRIX, 1.0, &F)); PetscCall(MatView(F, PETSC_VIEWER_STDOUT_WORLD)); PetscCall(MatIsDiagonal(F)); PetscCall(MatDestroy(&A)); PetscCall(MatDestroy(&D)); PetscCall(MatDestroy(&C)); PetscCall(MatDestroy(&F)); PetscCall(PetscRandomCreate(PETSC_COMM_SELF, &rctx)); PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size)); PetscCall(PetscMalloc1(size, &parts)); for (j = 0; j < 128; j++) { cnt = 0; for (i = 0; i < size - 1; i++) { PetscCall(PetscRandomGetValueReal(rctx, &rand)); parts[i] = (PetscInt)(N * rand); parts[i] = PetscMin(parts[i], N - cnt); cnt += parts[i]; } parts[size - 1] = N - cnt; PetscCall(PetscRandomGetValueReal(rctx, &rand)); nblocks = rand * 10; nblocks = PetscMax(nblocks, 2); cnt = 0; PetscCall(PetscMalloc1(nblocks, &blocksizes)); for (i = 0; i < nblocks - 1; i++) { PetscCall(PetscRandomGetValueReal(rctx, &rand)); blocksizes[i] = PetscMax(1, (PetscInt)(N * rand)); blocksizes[i] = PetscMin(blocksizes[i], N - cnt); cnt += blocksizes[i]; if (cnt == N) { nblocks = i + 1; break; } } if (cnt < N) blocksizes[nblocks - 1] = N - cnt; PetscCall(BuildMatrix(parts, nblocks, blocksizes, &A)); PetscCall(PetscFree(blocksizes)); PetscCall(MatInvertVariableBlockEnvelope(A, MAT_INITIAL_MATRIX, &D)); PetscCall(MatMatMult(A, D, MAT_INITIAL_MATRIX, 1.0, &F)); PetscCall(MatIsDiagonal(F)); PetscCall(MatDestroy(&A)); PetscCall(MatDestroy(&D)); PetscCall(MatDestroy(&F)); } PetscCall(PetscFree(parts)); PetscCall(PetscRandomDestroy(&rctx)); PetscCall(PetscFinalize()); return 0; } PetscErrorCode MatIsDiagonal(Mat A) { PetscInt ncols, i, j, rstart, rend; const PetscInt *cols; const PetscScalar *vals; PetscBool founddiag; PetscFunctionBeginUser; PetscCall(MatGetOwnershipRange(A, &rstart, &rend)); for (i = rstart; i < rend; i++) { founddiag = PETSC_FALSE; PetscCall(MatGetRow(A, i, &ncols, &cols, &vals)); for (j = 0; j < ncols; j++) { if (cols[j] == i) { PetscCheck(PetscAbsScalar(vals[j] - 1) < PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row %" PetscInt_FMT " does not have 1 on the diagonal, it has %g", i, (double)PetscAbsScalar(vals[j])); founddiag = PETSC_TRUE; } else { PetscCheck(PetscAbsScalar(vals[j]) < PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row %" PetscInt_FMT " has off-diagonal value %g at %" PetscInt_FMT, i, (double)PetscAbsScalar(vals[j]), cols[j]); } } PetscCall(MatRestoreRow(A, i, &ncols, &cols, &vals)); PetscCheck(founddiag, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Row %" PetscInt_FMT " does not have diagonal entry", i); } PetscFunctionReturn(PETSC_SUCCESS); } /* All processes receive all the block information */ PetscErrorCode BuildMatrix(const PetscInt *parts, PetscInt nblocks, const PetscInt *blocksizes, Mat *A) { PetscInt i, cnt = 0; PetscMPIInt rank; PetscFunctionBeginUser; PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank)); PetscCall(MatCreateAIJ(PETSC_COMM_WORLD, parts[rank], parts[rank], PETSC_DETERMINE, PETSC_DETERMINE, 0, NULL, 0, NULL, A)); PetscCall(MatSetOption(*A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE)); if (rank == 0) { for (i = 0; i < nblocks; i++) { PetscCall(MatSetValue(*A, cnt, cnt + blocksizes[i] - 1, 1.0, INSERT_VALUES)); PetscCall(MatSetValue(*A, cnt + blocksizes[i] - 1, cnt, 1.0, INSERT_VALUES)); cnt += blocksizes[i]; } } PetscCall(MatAssemblyBegin(*A, MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(*A, MAT_FINAL_ASSEMBLY)); PetscCall(MatShift(*A, 10)); PetscFunctionReturn(PETSC_SUCCESS); } /*TEST test: test: suffix: 2 nsize: 2 test: suffix: 5 nsize: 5 TEST*/