static char help[] = "Tests MatShift(), MatScale(), and MatDiagonalScale() for SHELL and NEST matrices\n\n"; #include typedef struct _n_User *User; struct _n_User { Mat B; }; static PetscErrorCode MatView_User(Mat A, PetscViewer viewer) { User user; PetscFunctionBegin; PetscCall(MatShellGetContext(A, &user)); PetscCall(MatView(user->B, viewer)); PetscFunctionReturn(0); } static PetscErrorCode MatMult_User(Mat A, Vec X, Vec Y) { User user; PetscFunctionBegin; PetscCall(MatShellGetContext(A, &user)); PetscCall(MatMult(user->B, X, Y)); PetscFunctionReturn(0); } static PetscErrorCode MatMultTranspose_User(Mat A, Vec X, Vec Y) { User user; PetscFunctionBegin; PetscCall(MatShellGetContext(A, &user)); PetscCall(MatMultTranspose(user->B, X, Y)); PetscFunctionReturn(0); } static PetscErrorCode MatGetDiagonal_User(Mat A, Vec X) { User user; PetscFunctionBegin; PetscCall(MatShellGetContext(A, &user)); PetscCall(MatGetDiagonal(user->B, X)); PetscFunctionReturn(0); } static PetscErrorCode TestMatrix(Mat A, Vec X, Vec Y, Vec Z) { Vec W1, W2, diff; Mat E; const char *mattypename; PetscViewer viewer = PETSC_VIEWER_STDOUT_WORLD; PetscScalar diag[2] = {2.9678190300000000e+08, 1.4173141580000000e+09}; PetscScalar multadd[2] = {-6.8966198500000000e+08, -2.0310609940000000e+09}; PetscScalar multtadd[2] = {-9.1052873900000000e+08, -1.8101942400000000e+09}; PetscReal nrm; PetscFunctionBegin; PetscCall(PetscObjectGetType((PetscObject)A, &mattypename)); PetscCall(PetscViewerASCIIPrintf(viewer, "\nMatrix of type: %s\n", mattypename)); PetscCall(VecDuplicate(X, &W1)); PetscCall(VecDuplicate(X, &W2)); PetscCall(MatScale(A, 31)); PetscCall(MatShift(A, 37)); PetscCall(MatDiagonalScale(A, X, Y)); PetscCall(MatScale(A, 41)); PetscCall(MatDiagonalScale(A, Y, Z)); PetscCall(MatComputeOperator(A, MATDENSE, &E)); PetscCall(MatView(E, viewer)); PetscCall(PetscViewerASCIIPrintf(viewer, "Testing MatMult + MatMultTranspose\n")); PetscCall(MatMult(A, Z, W1)); PetscCall(MatMultTranspose(A, W1, W2)); PetscCall(VecView(W2, viewer)); PetscCall(PetscViewerASCIIPrintf(viewer, "Testing MatMultAdd\n")); PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, 2, multadd, &diff)); PetscCall(VecSet(W1, -1.0)); PetscCall(MatMultAdd(A, W1, W1, W2)); PetscCall(VecView(W2, viewer)); PetscCall(VecAXPY(W2, -1.0, diff)); PetscCall(VecNorm(W2, NORM_2, &nrm)); #if defined(PETSC_USE_REAL_DOUBLE) || defined(PETSC_USE_REAL___FLOAT128) PetscCheck(nrm <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatMultAdd(A,x,x,y) produces incorrect result"); #endif PetscCall(VecSet(W2, -1.0)); PetscCall(MatMultAdd(A, W1, W2, W2)); PetscCall(VecView(W2, viewer)); PetscCall(VecAXPY(W2, -1.0, diff)); PetscCall(VecNorm(W2, NORM_2, &nrm)); #if defined(PETSC_USE_REAL_DOUBLE) || defined(PETSC_USE_REAL___FLOAT128) PetscCheck(nrm <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatMultAdd(A,x,y,y) produces incorrect result"); #endif PetscCall(VecDestroy(&diff)); PetscCall(PetscViewerASCIIPrintf(viewer, "Testing MatMultTransposeAdd\n")); PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, 2, multtadd, &diff)); PetscCall(VecSet(W1, -1.0)); PetscCall(MatMultTransposeAdd(A, W1, W1, W2)); PetscCall(VecView(W2, viewer)); PetscCall(VecAXPY(W2, -1.0, diff)); PetscCall(VecNorm(W2, NORM_2, &nrm)); #if defined(PETSC_USE_REAL_DOUBLE) || defined(PETSC_USE_REAL___FLOAT128) PetscCheck(nrm <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatMultTransposeAdd(A,x,x,y) produces incorrect result"); #endif PetscCall(VecSet(W2, -1.0)); PetscCall(MatMultTransposeAdd(A, W1, W2, W2)); PetscCall(VecView(W2, viewer)); PetscCall(VecAXPY(W2, -1.0, diff)); PetscCall(VecNorm(W2, NORM_2, &nrm)); #if defined(PETSC_USE_REAL_DOUBLE) || defined(PETSC_USE_REAL___FLOAT128) PetscCheck(nrm <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatMultTransposeAdd(A,x,y,y) produces incorrect result"); #endif PetscCall(VecDestroy(&diff)); PetscCall(PetscViewerASCIIPrintf(viewer, "Testing MatGetDiagonal\n")); PetscCall(MatGetDiagonal(A, W2)); PetscCall(VecView(W2, viewer)); PetscCall(VecCreateSeqWithArray(PETSC_COMM_SELF, 1, 2, diag, &diff)); PetscCall(VecAXPY(diff, -1.0, W2)); PetscCall(VecNorm(diff, NORM_2, &nrm)); PetscCheck(nrm <= PETSC_SMALL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "MatGetDiagonal() produces incorrect result"); PetscCall(VecDestroy(&diff)); /* MATSHELL does not support MatDiagonalSet after MatScale */ if (strncmp(mattypename, "shell", 5)) { PetscCall(MatDiagonalSet(A, X, INSERT_VALUES)); PetscCall(MatGetDiagonal(A, W1)); PetscCall(VecView(W1, viewer)); } else { PetscCall(PetscViewerASCIIPrintf(viewer, "MatDiagonalSet not tested on MATSHELL\n")); } PetscCall(MatDestroy(&E)); PetscCall(VecDestroy(&W1)); PetscCall(VecDestroy(&W2)); PetscFunctionReturn(0); } int main(int argc, char **args) { const PetscScalar xvals[] = {11, 13}, yvals[] = {17, 19}, zvals[] = {23, 29}; const PetscInt inds[] = {0, 1}; PetscScalar avals[] = {2, 3, 5, 7}; Mat A, S, D[4], N; Vec X, Y, Z; User user; PetscInt i; PetscFunctionBeginUser; PetscCall(PetscInitialize(&argc, &args, (char *)0, help)); PetscCall(MatCreateSeqAIJ(PETSC_COMM_WORLD, 2, 2, 2, NULL, &A)); PetscCall(MatSetUp(A)); PetscCall(MatSetValues(A, 2, inds, 2, inds, avals, INSERT_VALUES)); PetscCall(VecCreateSeq(PETSC_COMM_WORLD, 2, &X)); PetscCall(VecDuplicate(X, &Y)); PetscCall(VecDuplicate(X, &Z)); PetscCall(VecSetValues(X, 2, inds, xvals, INSERT_VALUES)); PetscCall(VecSetValues(Y, 2, inds, yvals, INSERT_VALUES)); PetscCall(VecSetValues(Z, 2, inds, zvals, INSERT_VALUES)); PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); PetscCall(VecAssemblyBegin(X)); PetscCall(VecAssemblyBegin(Y)); PetscCall(VecAssemblyBegin(Z)); PetscCall(VecAssemblyEnd(X)); PetscCall(VecAssemblyEnd(Y)); PetscCall(VecAssemblyEnd(Z)); PetscCall(PetscNew(&user)); user->B = A; PetscCall(MatCreateShell(PETSC_COMM_WORLD, 2, 2, 2, 2, user, &S)); PetscCall(MatSetUp(S)); PetscCall(MatShellSetOperation(S, MATOP_VIEW, (void (*)(void))MatView_User)); PetscCall(MatShellSetOperation(S, MATOP_MULT, (void (*)(void))MatMult_User)); PetscCall(MatShellSetOperation(S, MATOP_MULT_TRANSPOSE, (void (*)(void))MatMultTranspose_User)); PetscCall(MatShellSetOperation(S, MATOP_GET_DIAGONAL, (void (*)(void))MatGetDiagonal_User)); for (i = 0; i < 4; i++) { PetscCall(MatCreateSeqDense(PETSC_COMM_WORLD, 1, 1, &avals[i], &D[i])); } PetscCall(MatCreateNest(PETSC_COMM_WORLD, 2, NULL, 2, NULL, D, &N)); PetscCall(MatSetUp(N)); PetscCall(TestMatrix(S, X, Y, Z)); PetscCall(TestMatrix(A, X, Y, Z)); PetscCall(TestMatrix(N, X, Y, Z)); for (i = 0; i < 4; i++) PetscCall(MatDestroy(&D[i])); PetscCall(MatDestroy(&A)); PetscCall(MatDestroy(&S)); PetscCall(MatDestroy(&N)); PetscCall(VecDestroy(&X)); PetscCall(VecDestroy(&Y)); PetscCall(VecDestroy(&Z)); PetscCall(PetscFree(user)); PetscCall(PetscFinalize()); return 0; } /*TEST test: TEST*/