1c4762a1bSJed Brown static char help[] = "Tests MatSolve(), MatSolveTranspose() and MatMatSolve() with SEQDENSE\n";
2c4762a1bSJed Brown
3c4762a1bSJed Brown #include <petscmat.h>
4c4762a1bSJed Brown
main(int argc,char ** args)5d71ae5a4SJacob Faibussowitsch int main(int argc, char **args)
6d71ae5a4SJacob Faibussowitsch {
7c4762a1bSJed Brown Mat A, RHS, C, F, X;
8c4762a1bSJed Brown Vec u, x, b;
9c4762a1bSJed Brown PetscMPIInt size;
10c4762a1bSJed Brown PetscInt m, n, nsolve, nrhs;
11c4762a1bSJed Brown PetscReal norm, tol = PETSC_SQRT_MACHINE_EPSILON;
12c4762a1bSJed Brown PetscRandom rand;
13c4762a1bSJed Brown PetscBool data_provided, herm, symm, hpd;
14c4762a1bSJed Brown MatFactorType ftyp;
15c4762a1bSJed Brown PetscViewer fd;
16c4762a1bSJed Brown char file[PETSC_MAX_PATH_LEN];
17c4762a1bSJed Brown
18327415f7SBarry Smith PetscFunctionBeginUser;
19c8025a54SPierre Jolivet PetscCall(PetscInitialize(&argc, &args, NULL, help));
209566063dSJacob Faibussowitsch PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
21be096a46SBarry Smith PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "This is a uniprocessor test");
22c4762a1bSJed Brown /* Determine which type of solver we want to test for */
23c4762a1bSJed Brown herm = PETSC_FALSE;
24c4762a1bSJed Brown symm = PETSC_FALSE;
25c4762a1bSJed Brown hpd = PETSC_FALSE;
269566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(NULL, NULL, "-symmetric_solve", &symm, NULL));
279566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(NULL, NULL, "-hermitian_solve", &herm, NULL));
289566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetBool(NULL, NULL, "-hpd_solve", &hpd, NULL));
29c4762a1bSJed Brown
30c4762a1bSJed Brown /* Determine file from which we read the matrix A */
31c4762a1bSJed Brown ftyp = MAT_FACTOR_LU;
329566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetString(NULL, NULL, "-f", file, sizeof(file), &data_provided));
33c4762a1bSJed Brown if (!data_provided) { /* get matrices from PETSc distribution */
34c6a7a370SJeremy L Thompson PetscCall(PetscStrncpy(file, "${PETSC_DIR}/share/petsc/datafiles/matrices/", sizeof(file)));
35c4762a1bSJed Brown if (hpd) {
36c4762a1bSJed Brown #if defined(PETSC_USE_COMPLEX)
37c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "hpd-complex-", sizeof(file)));
38c4762a1bSJed Brown #else
39c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "spd-real-", sizeof(file)));
40c4762a1bSJed Brown #endif
41c4762a1bSJed Brown ftyp = MAT_FACTOR_CHOLESKY;
42c4762a1bSJed Brown } else {
43c4762a1bSJed Brown #if defined(PETSC_USE_COMPLEX)
44c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "nh-complex-", sizeof(file)));
45c4762a1bSJed Brown #else
46c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "ns-real-", sizeof(file)));
47c4762a1bSJed Brown #endif
48c4762a1bSJed Brown }
49c4762a1bSJed Brown #if defined(PETSC_USE_64BIT_INDICES)
50c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "int64-", sizeof(file)));
51c4762a1bSJed Brown #else
52c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "int32-", sizeof(file)));
53c4762a1bSJed Brown #endif
54c4762a1bSJed Brown #if defined(PETSC_USE_REAL_SINGLE)
55c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "float32", sizeof(file)));
56c4762a1bSJed Brown #else
57c6a7a370SJeremy L Thompson PetscCall(PetscStrlcat(file, "float64", sizeof(file)));
58c4762a1bSJed Brown #endif
59c4762a1bSJed Brown }
60c4762a1bSJed Brown
61c4762a1bSJed Brown /* Load matrix A */
62c4762a1bSJed Brown #if defined(PETSC_USE_REAL___FLOAT128)
639566063dSJacob Faibussowitsch PetscCall(PetscOptionsInsertString(NULL, "-binary_read_double"));
64c4762a1bSJed Brown #endif
659566063dSJacob Faibussowitsch PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD, file, FILE_MODE_READ, &fd));
669566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_WORLD, &A));
679566063dSJacob Faibussowitsch PetscCall(MatLoad(A, fd));
689566063dSJacob Faibussowitsch PetscCall(PetscViewerDestroy(&fd));
699566063dSJacob Faibussowitsch PetscCall(MatConvert(A, MATSEQDENSE, MAT_INPLACE_MATRIX, &A));
709566063dSJacob Faibussowitsch PetscCall(MatGetSize(A, &m, &n));
7108401ef6SPierre Jolivet PetscCheck(m == n, PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "This example is not intended for rectangular matrices (%" PetscInt_FMT ", %" PetscInt_FMT ")", m, n);
72c4762a1bSJed Brown
73a5b23f4aSJose E. Roman /* Create dense matrix C and X; C holds true solution with identical columns */
74c4762a1bSJed Brown nrhs = 2;
759566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetInt(NULL, NULL, "-nrhs", &nrhs, NULL));
769566063dSJacob Faibussowitsch PetscCall(MatCreate(PETSC_COMM_WORLD, &C));
779566063dSJacob Faibussowitsch PetscCall(MatSetSizes(C, m, PETSC_DECIDE, PETSC_DECIDE, nrhs));
789566063dSJacob Faibussowitsch PetscCall(MatSetType(C, MATDENSE));
799566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(C));
809566063dSJacob Faibussowitsch PetscCall(MatSetUp(C));
81c4762a1bSJed Brown
829566063dSJacob Faibussowitsch PetscCall(PetscRandomCreate(PETSC_COMM_WORLD, &rand));
839566063dSJacob Faibussowitsch PetscCall(PetscRandomSetFromOptions(rand));
849566063dSJacob Faibussowitsch PetscCall(MatSetRandom(C, rand));
859566063dSJacob Faibussowitsch PetscCall(MatDuplicate(C, MAT_DO_NOT_COPY_VALUES, &X));
869566063dSJacob Faibussowitsch PetscCall(MatDuplicate(C, MAT_DO_NOT_COPY_VALUES, &RHS));
87c4762a1bSJed Brown
88c4762a1bSJed Brown /* Create vectors */
899566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_WORLD, &x));
909566063dSJacob Faibussowitsch PetscCall(VecSetSizes(x, n, PETSC_DECIDE));
919566063dSJacob Faibussowitsch PetscCall(VecSetFromOptions(x));
929566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &b));
939566063dSJacob Faibussowitsch PetscCall(VecDuplicate(x, &u)); /* save the true solution */
94c4762a1bSJed Brown
95c4762a1bSJed Brown /* make a symmetric matrix */
96c4762a1bSJed Brown if (symm) {
97c4762a1bSJed Brown Mat AT;
98c4762a1bSJed Brown
999566063dSJacob Faibussowitsch PetscCall(MatTranspose(A, MAT_INITIAL_MATRIX, &AT));
1009566063dSJacob Faibussowitsch PetscCall(MatAXPY(A, 1.0, AT, SAME_NONZERO_PATTERN));
1019566063dSJacob Faibussowitsch PetscCall(MatDestroy(&AT));
102c4762a1bSJed Brown ftyp = MAT_FACTOR_CHOLESKY;
103c4762a1bSJed Brown }
104c4762a1bSJed Brown /* make an hermitian matrix */
105c4762a1bSJed Brown if (herm) {
106c4762a1bSJed Brown Mat AH;
107c4762a1bSJed Brown
1089566063dSJacob Faibussowitsch PetscCall(MatHermitianTranspose(A, MAT_INITIAL_MATRIX, &AH));
1099566063dSJacob Faibussowitsch PetscCall(MatAXPY(A, 1.0, AH, SAME_NONZERO_PATTERN));
1109566063dSJacob Faibussowitsch PetscCall(MatDestroy(&AH));
111c4762a1bSJed Brown ftyp = MAT_FACTOR_CHOLESKY;
112c4762a1bSJed Brown }
1139566063dSJacob Faibussowitsch PetscCall(PetscObjectSetName((PetscObject)A, "A"));
1149566063dSJacob Faibussowitsch PetscCall(MatViewFromOptions(A, NULL, "-amat_view"));
115c4762a1bSJed Brown
1169566063dSJacob Faibussowitsch PetscCall(MatDuplicate(A, MAT_COPY_VALUES, &F));
1179566063dSJacob Faibussowitsch PetscCall(MatSetOption(F, MAT_SYMMETRIC, symm));
118c4762a1bSJed Brown /* it seems that the SPD concept in PETSc extends naturally to Hermitian Positive definitess */
1199566063dSJacob Faibussowitsch PetscCall(MatSetOption(F, MAT_HERMITIAN, (PetscBool)(hpd || herm)));
1209566063dSJacob Faibussowitsch PetscCall(MatSetOption(F, MAT_SPD, hpd));
1214396437dSToby Isaac {
1224396437dSToby Isaac PetscInt iftyp = ftyp;
1239566063dSJacob Faibussowitsch PetscCall(PetscOptionsGetEList(NULL, NULL, "-ftype", MatFactorTypes, MAT_FACTOR_NUM_TYPES, &iftyp, NULL));
1244396437dSToby Isaac ftyp = (MatFactorType)iftyp;
1254396437dSToby Isaac }
126c4762a1bSJed Brown if (ftyp == MAT_FACTOR_LU) {
1279566063dSJacob Faibussowitsch PetscCall(MatLUFactor(F, NULL, NULL, NULL));
1284396437dSToby Isaac } else if (ftyp == MAT_FACTOR_CHOLESKY) {
1299566063dSJacob Faibussowitsch PetscCall(MatCholeskyFactor(F, NULL, NULL));
1304396437dSToby Isaac } else if (ftyp == MAT_FACTOR_QR) {
1319566063dSJacob Faibussowitsch PetscCall(MatQRFactor(F, NULL, NULL));
13298921bdaSJacob Faibussowitsch } else SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_SUP, "Factorization %s not supported in this example", MatFactorTypes[ftyp]);
133c4762a1bSJed Brown
134c4762a1bSJed Brown for (nsolve = 0; nsolve < 2; nsolve++) {
1359566063dSJacob Faibussowitsch PetscCall(VecSetRandom(x, rand));
1369566063dSJacob Faibussowitsch PetscCall(VecCopy(x, u));
137c4762a1bSJed Brown if (nsolve) {
1389566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, b));
1399566063dSJacob Faibussowitsch PetscCall(MatSolve(F, b, x));
140c4762a1bSJed Brown } else {
1419566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, b));
1429566063dSJacob Faibussowitsch PetscCall(MatSolveTranspose(F, b, x));
143c4762a1bSJed Brown }
144c4762a1bSJed Brown /* Check the error */
1459566063dSJacob Faibussowitsch PetscCall(VecAXPY(u, -1.0, x)); /* u <- (-1.0)x + u */
1469566063dSJacob Faibussowitsch PetscCall(VecNorm(u, NORM_2, &norm));
147c4762a1bSJed Brown if (norm > tol) {
148c4762a1bSJed Brown PetscReal resi;
149c4762a1bSJed Brown if (nsolve) {
1509566063dSJacob Faibussowitsch PetscCall(MatMult(A, x, u)); /* u = A*x */
151c4762a1bSJed Brown } else {
1529566063dSJacob Faibussowitsch PetscCall(MatMultTranspose(A, x, u)); /* u = A*x */
153c4762a1bSJed Brown }
1549566063dSJacob Faibussowitsch PetscCall(VecAXPY(u, -1.0, b)); /* u <- (-1.0)b + u */
1559566063dSJacob Faibussowitsch PetscCall(VecNorm(u, NORM_2, &resi));
156c4762a1bSJed Brown if (nsolve) {
1579566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "MatSolve error: Norm of error %g, residual %g\n", (double)norm, (double)resi));
158c4762a1bSJed Brown } else {
1599566063dSJacob Faibussowitsch PetscCall(PetscPrintf(PETSC_COMM_SELF, "MatSolveTranspose error: Norm of error %g, residual %g\n", (double)norm, (double)resi));
160c4762a1bSJed Brown }
161c4762a1bSJed Brown }
162c4762a1bSJed Brown }
1639566063dSJacob Faibussowitsch PetscCall(MatMatMult(A, C, MAT_REUSE_MATRIX, 2.0, &RHS));
1649566063dSJacob Faibussowitsch PetscCall(MatMatSolve(F, RHS, X));
165c4762a1bSJed Brown
166c4762a1bSJed Brown /* Check the error */
1679566063dSJacob Faibussowitsch PetscCall(MatAXPY(X, -1.0, C, SAME_NONZERO_PATTERN));
1689566063dSJacob Faibussowitsch PetscCall(MatNorm(X, NORM_FROBENIUS, &norm));
16948a46eb9SPierre Jolivet if (norm > tol) PetscCall(PetscPrintf(PETSC_COMM_SELF, "MatMatSolve: Norm of error %g\n", (double)norm));
170c4762a1bSJed Brown
171c4762a1bSJed Brown /* Free data structures */
1729566063dSJacob Faibussowitsch PetscCall(MatDestroy(&A));
1739566063dSJacob Faibussowitsch PetscCall(MatDestroy(&C));
1749566063dSJacob Faibussowitsch PetscCall(MatDestroy(&F));
1759566063dSJacob Faibussowitsch PetscCall(MatDestroy(&X));
1769566063dSJacob Faibussowitsch PetscCall(MatDestroy(&RHS));
1779566063dSJacob Faibussowitsch PetscCall(PetscRandomDestroy(&rand));
1789566063dSJacob Faibussowitsch PetscCall(VecDestroy(&x));
1799566063dSJacob Faibussowitsch PetscCall(VecDestroy(&b));
1809566063dSJacob Faibussowitsch PetscCall(VecDestroy(&u));
1819566063dSJacob Faibussowitsch PetscCall(PetscFinalize());
182b122ec5aSJacob Faibussowitsch return 0;
183c4762a1bSJed Brown }
184c4762a1bSJed Brown
185c4762a1bSJed Brown /*TEST
186c4762a1bSJed Brown
187c4762a1bSJed Brown testset:
188*3886731fSPierre Jolivet output_file: output/empty.out
189c4762a1bSJed Brown test:
190c4762a1bSJed Brown suffix: ns
191c4762a1bSJed Brown test:
192c4762a1bSJed Brown suffix: sym
193c4762a1bSJed Brown args: -symmetric_solve
194c4762a1bSJed Brown test:
195c4762a1bSJed Brown suffix: herm
196c4762a1bSJed Brown args: -hermitian_solve
197c4762a1bSJed Brown test:
198c4762a1bSJed Brown suffix: hpd
199c4762a1bSJed Brown args: -hpd_solve
2004396437dSToby Isaac test:
2014396437dSToby Isaac suffix: qr
2024396437dSToby Isaac args: -ftype qr
203c4762a1bSJed Brown
204c4762a1bSJed Brown TEST*/
205