/* nag_sparse_real_symm_precon_ichol_solve (f11jbc) Example Program.
*
* Copyright 2024 Numerical Algorithms Group.
*
* Mark 30.0, 2024.
*/
#include <nag.h>
void do_rcm(Integer n, Integer nnz, Integer *irow, Integer *icol, double *a,
double *y, Integer *istr, Integer *perm_fwd, Integer *perm_inv);
int main(void) {
/* Scalars */
Integer exit_status = 0;
double dscale, dtol;
Integer i, la, lfill, n, nnz, nnzc, npivm;
/* Arrays */
double *a = 0, *x = 0, *y = 0;
Integer *icol = 0, *ipiv = 0, *irow = 0, *istr = 0, *perm_fwd = 0,
*perm_inv = 0;
/* NAG types */
Nag_SparseSym_Fact mic;
Nag_SparseSym_Piv pstrat;
Nag_SparseSym_CheckData check;
Nag_Sparse_Comm comm;
NagError fail;
INIT_FAIL(fail);
printf(
"nag_sparse_real_symm_precon_ichol_solve (f11jbc) Example Program Results");
printf("\n");
/* Skip heading in data file */
scanf("%*[^\n]");
/* Read order of matrix and number of nonzero entries */
scanf("%" NAG_IFMT "%*[^\n]", &n);
scanf("%" NAG_IFMT "%*[^\n]", &nnz);
/* Allocate memory */
la = 3 * nnz;
if (!(a = NAG_ALLOC(la, double)) || !(x = NAG_ALLOC(n, double)) ||
!(y = NAG_ALLOC(n, double)) || !(icol = NAG_ALLOC(la, Integer)) ||
!(ipiv = NAG_ALLOC(n, Integer)) || !(irow = NAG_ALLOC(la, Integer)) ||
!(istr = NAG_ALLOC(n + 1, Integer)) ||
!(perm_fwd = NAG_ALLOC(n, Integer)) ||
!(perm_inv = NAG_ALLOC(n, Integer))) {
printf("Allocation failure\n");
exit_status = -1;
goto END;
}
/* Read the matrix A */
for (i = 0; i < nnz; i++)
scanf("%lf%" NAG_IFMT "%" NAG_IFMT "%*[^\n]", &a[i], &irow[i], &icol[i]);
/* Read the vector y */
for (i = 0; i < n; i++)
scanf("%lf", &y[i]);
lfill = -1;
dtol = 0.0;
dscale = 0.0;
mic = Nag_SparseSym_UnModFact;
pstrat = Nag_SparseSym_MarkPiv;
/* Calculate Cholesky factorization using
* nag_sparse_real_symm_precon_ichol (f11jac).
*/
nag_sparse_real_symm_precon_ichol(n, nnz, &a, &la, &irow, &icol, lfill, dtol,
mic, dscale, pstrat, ipiv, istr, &nnzc,
&npivm, &comm, &fail);
if (fail.code != NE_NOERROR) {
printf("Error from nag_sparse_real_symm_precon_ichol (f11jac).\n%s\n",
fail.message);
exit_status = 1;
goto END;
}
/* Check the output value of npivm */
if (npivm != 0)
printf("Factorization is not complete \n");
else {
/* Solve linear system involving incomplete Cholesky factorization
*
* T T
* P L D L P x = y
*
* using nag_sparse_real_symm_precon_ichol_solve (f11jbc).
*/
check = Nag_SparseSym_Check;
nag_sparse_real_symm_precon_ichol_solve(n, a, la, irow, icol, ipiv, istr,
check, y, x, &fail);
if (fail.code != NE_NOERROR) {
printf(
"Error from nag_sparse_real_symm_precon_ichol_solve (f11jbc).\n%s\n",
fail.message);
exit_status = 2;
goto END;
}
/* Output results */
printf(" Solution of linear system \n");
for (i = 0; i < n; i++)
printf("%16.4e\n", x[i]);
printf("\n");
}
/* Repeat with Cuthill-McKee permutation
* Compute reverse Cuthill-McKee permutation for bandwidth reduction
*/
do_rcm(n, nnz, irow, icol, a, y, istr, perm_fwd, perm_inv);
SET_FAIL(fail);
nag_sparse_real_symm_precon_ichol(n, nnz, &a, &la, &irow, &icol, lfill, dtol,
mic, dscale, pstrat, ipiv, istr, &nnzc,
&npivm, &comm, &fail);
if (npivm != 0)
printf("Factorization is not complete \n");
else {
check = Nag_SparseSym_Check;
nag_sparse_real_symm_precon_ichol_solve(n, a, la, irow, icol, ipiv, istr,
check, y, x, &fail);
printf(" Solution of linear system with Reverse Cuthill-McKee\n");
for (i = 0; i < n; i++)
printf("%16.4e\n", x[perm_inv[i] - 1]);
printf("\n");
}
END:
NAG_FREE(a);
NAG_FREE(x);
NAG_FREE(y);
NAG_FREE(icol);
NAG_FREE(ipiv);
NAG_FREE(irow);
NAG_FREE(istr);
NAG_FREE(perm_fwd);
NAG_FREE(perm_inv);
return exit_status;
}
void do_rcm(Integer n, Integer nnz, Integer *irow, Integer *icol, double *a,
double *y, Integer *istr, Integer *perm_fwd, Integer *perm_inv) {
Integer j, i, nnz_cs, nnz_scs, info[4], mask[1];
double *yy;
Nag_Boolean lopts[5] = {Nag_FALSE, Nag_FALSE, Nag_TRUE, Nag_TRUE, Nag_TRUE};
NagError fail;
SET_FAIL(fail);
yy = NAG_ALLOC(n, double);
/* SCS to CS, must add the upper triangle entries. */
j = nnz;
for (i = 0; i < nnz; i++) {
if (irow[i] > icol[i]) {
/* strictly lower triangle, add the transposed */
a[j] = a[i];
irow[j] = icol[i];
icol[j] = irow[i];
j++;
}
}
nnz_cs = j;
/* Reorder, CS to CCS, icolzp in istr */
nag_sparse_real_gen_sort(n, &nnz_cs, a, icol, irow, Nag_SparseNsym_FailDups,
Nag_SparseNsym_FailZeros, istr, &fail);
/* Calculate reverse Cuthill-McKee */
nag_sparse_sym_rcm(n, nnz_cs, istr, irow, lopts, mask, perm_fwd, info, &fail);
/* compute inverse perm, in perm_inv */
for (i = 0; i < n; i++)
perm_inv[perm_fwd[i] - 1] = i + 1;
/* Apply permutation on column/row indices */
for (i = 0; i < nnz_cs; i++) {
icol[i] = perm_inv[icol[i] - 1];
irow[i] = perm_inv[irow[i] - 1];
}
/* restrict to lower triangle, SCS format
* copying entries upwards
*/
j = 0;
for (i = 0; i < nnz_cs; i++) {
if (irow[i] >= icol[i]) {
/* non-upper triangle, bubble up */
a[j] = a[i];
icol[j] = icol[i];
irow[j] = irow[i];
j++;
}
}
nnz_scs = j;
/* sort */
nag_sparse_real_symm_sort(n, &nnz_scs, a, irow, icol, Nag_SparseSym_SumDups,
Nag_SparseSym_KeepZeros, istr, &fail);
/* permute rhs vector */
for (i = 0; i < n; i++)
yy[i] = y[perm_fwd[i] - 1];
for (i = 0; i < n; i++)
y[i] = yy[i];
NAG_FREE(yy);
}