Iterative Linear System Solvers - Iterative Linear System Solvers - 5.0 English - 63865

AOCL Sparse Library (63865)

Document ID
63865
Release Date
2024-10-09
Version
5.0 English

Iterative Linear System Solvers#

Introduction of Iterative Solver Suite (itsol)#

AOCL-Sparse Iterative Solver Suite (itsol) is an iterative framework for solving large-scale sparse linear systems of equations of the form

\[Ax=b,\]

where \(A\) is a sparse full-rank square matrix of size \(n\) by \(n\), \(b\) is a dense \(n\)-vector, and \(x\) is the vector of unknowns also of size \(n\). The framework solves the previous problem using either the Conjugate Gradient method or GMRES. It supports a variety of preconditioners (accelerators) such as Symmetric Gauss-Seidel or Incomplete LU factorization, ILU(0).

Iterative solvers at each step (iteration) find a better approximation to the solution of the linear system of equations in the sense that it reduces an error metric. In contrast, direct solvers only provide a solution once the full algorithm as been executed. A great advantage of iterative solvers is that they can be interrupted once an approximate solution is deemed acceptable.

Forward and Reverse Communication Interfaces#

The suite presents two separate interfaces to all the iterative solvers, a direct one, aoclsparse_itsol_d_solve() (aoclsparse_itsol_s_solve()), and a reverse communication (RCI) one aoclsparse_itsol_d_rci_solve() (aoclsparse_itsol_s_rci_solve()). While the underlying algorithms are exactly the same, the difference lies in how data is communicated to the solvers.

The direct communication interface expects to have explicit access to the coefficient matrix \(A\). On the other hand, the reverse communication interface makes no assumption on the matrix storage. Thus when the solver requires some matrix operation such as a matrix-vector product, it returns control to the user and asks the user perform the operation and provide the results by calling again the RCI solver.

Information Array#

The array rinfo[100] is used by the solvers (e.g. aoclsparse_itsol_s_solve() or aoclsparse_itsol_d_rci_solve()) to report back useful convergence metrics and other solver statistics. The user callback monit is also equipped with this array and can be used to view or monitor the state of the solver. The solver will populate the following entries with the most recent iteration data

Index

Description

0

Absolute residual norm, \(r_{\text{abs}} = \| Ax-b\|_2\).

1

Norm of the right-hand side vector \(b\), \(\|b\|_2\).

2-29

Reserved for future use.

30

Iteration counter.

31-99

Reserved for future use.

References#

API documentation#

aoclsparse_itsol_rci_job#

enum aoclsparse_itsol_rci_job#

Values of ircomm used by the iterative solver reverse communication interface (RCI) aoclsparse_itsol_d_rci_solve and aoclsparse_itsol_s_rci_solve to communicate back to the user which operation is required.

Values:

enumerator aoclsparse_rci_interrupt#

if set by the user, signals the solver to terminate. This is never set by the solver. Terminate.

enumerator aoclsparse_rci_stop#

found a solution within specified tolerance (see options “cg rel tolerance”, “cg abs tolerance”, “gmres rel tolerance”, and “gmres abs tolerance” in Options). Terminate, vector x contains the solution.

enumerator aoclsparse_rci_start#

initial value of the ircomm flag, no action required. Call solver.

enumerator aoclsparse_rci_mv#

perform the matrix-vector product \( v = Au\). Return control to solver.

enumerator aoclsparse_rci_precond#

perform a preconditioning step on the vector \(u\) and store in \(v\). If the preconditioner \(M\) has explicit matrix form, then applying the preconditioner would result in the operations \( v=Mu \) or \(v=M^{-1}u\). The latter would be performed by solving the linear system of equations \(Mv=u\). Return control to solver.

enumerator aoclsparse_rci_stopping_criterion#

perform a monitoring step and check for custom stopping criteria. If using a positive tolerance value for the convergence options (see aoclsparse_rci_stop), then this step can be ignored and control can be returned to solver.

aoclsparse_itsol_?_init()#

aoclsparse_status aoclsparse_itsol_s_init(aoclsparse_itsol_handle *handle)#
aoclsparse_status aoclsparse_itsol_d_init(aoclsparse_itsol_handle *handle)#

Initialize a problem handle ( aoclsparse_itsol_handle) for the iterative solvers suite of the library.

aoclsparse_itsol_s_init and aoclsparse_itsol_d_init initialize a data structure referred to as problem handle. This handle is used by iterative solvers (itsol) suite to setup options, define which solver to use, etc.

Note

Once the handle is no longer needed, it can be destroyed and the memory released by calling aoclsparse_itsol_destroy.

Parameters

handle[inout] the pointer to the problem handle data structure.

Return values
  • aoclsparse_status_success – the operation completed successfully.

  • aoclsparse_status_memory_error – internal memory allocation error.

  • aoclsparse_status_invalid_pointer – the pointer to the problem handle is invalid.

  • aoclsparse_status_internal_error – an unexpected error occurred.

aoclsparse_itsol_destroy()#

void aoclsparse_itsol_destroy(aoclsparse_itsol_handle *handle)#

Free the memory reserved in a problem handle previously initialized by aoclsparse_itsol_s_init or aoclsparse_itsol_d_init.

Once the problem handle is no longer needed, calling this function to deallocate the memory is advisable to avoid memory leaks.

Note

Passing a handle that has not been initialized by aoclsparse_itsol_s_init or aoclsparse_itsol_d_init may have unpredictable results.

Parameters

handle[inout] pointer to a problem handle.

aoclsparse_itsol_?_solve()#

aoclsparse_status aoclsparse_itsol_s_solve(aoclsparse_itsol_handle handle, aoclsparse_int n, aoclsparse_matrix mat, const aoclsparse_mat_descr descr, const float *b, float *x, float rinfo[100], aoclsparse_int precond(aoclsparse_int flag, aoclsparse_int n, const float *u, float *v, void *udata), aoclsparse_int monit(aoclsparse_int n, const float *x, const float *r, float rinfo[100], void *udata), void *udata)#
aoclsparse_status aoclsparse_itsol_d_solve(aoclsparse_itsol_handle handle, aoclsparse_int n, aoclsparse_matrix mat, const aoclsparse_mat_descr descr, const double *b, double *x, double rinfo[100], aoclsparse_int precond(aoclsparse_int flag, aoclsparse_int n, const double *u, double *v, void *udata), aoclsparse_int monit(aoclsparse_int n, const double *x, const double *r, double rinfo[100], void *udata), void *udata)#

Forward communication interface to the iterative solvers suite of the library.

This function solves the linear system of equations

\[ Ax=b, \]
where the matrix of coefficients \(A\) is defined by mat. The right hand-side is the dense vector b and the vector of unknowns is x. If \(A\) is symmetric and positive definite then set the option “iterative method” to “cg” to solve the problem using the Conjugate Gradient method, alternatively set the option to “gmres” to solve using GMRes. See the Options for a list of available options to modify the behaviour of each solver.

The expected workflow is as follows:

  1. Call aoclsparse_itsol_s_init or aoclsparse_itsol_d_init to initialize the problem handle ( aoclsparse_itsol_handle).

  2. Choose the solver and adjust its behaviour by setting optional parameters with aoclsparse_itsol_option_set, see also Options.

  3. Solve the system by calling aoclsparse_itsol_s_solve or aoclsparse_itsol_d_solve.

  4. If there is another linear system of equations to solve with the same matrix but a different right-hand side \(b\), then repeat from step 3.

  5. If solver terminated successfully then vector x contains the solution.

  6. Free the memory with aoclsparse_itsol_destroy.

This interface requires to explicitly provide the matrix \(A\) and its descriptor descr, this kind of interface is also known as _forward communication_ which contrasts with *reverse communication* in which case the matrix \(A\) and its descriptor descr need not be explicitly available. For more details on the latter, see aoclsparse_itsol_d_rci_solve or aoclsparse_itsol_s_rci_solve.

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <iomanip>
 27#include <iostream>
 28#include <math.h>
 29#include <vector>
 30
 31aoclsparse_int monit(aoclsparse_int n,
 32                     const double  *x,
 33                     const double  *r __attribute__((unused)),
 34                     double        *rinfo,
 35                     void          *udata __attribute((unused)))
 36{
 37    int                     it  = (int)rinfo[30];
 38    std::ios_base::fmtflags fmt = std::cout.flags();
 39    fmt |= std::ios_base::scientific | std::ios_base::right | std::ios_base::showpos;
 40    if(!(it % 10))
 41    {
 42        std::cout << std::setw(5) << std::right << " iter"
 43                  << " " << std::setw(16) << std::right << "optim";
 44        for(int i = 0; i < n; i++)
 45            std::cout << std::setw(8) << std::right << "x[" << i << "]";
 46        std::cout << std::endl;
 47    }
 48    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 49              << std::scientific << std::setprecision(8) << rinfo[0];
 50    std::cout << std::setprecision(2) << std::showpos;
 51    for(int i = 0; i < n; i++)
 52        std::cout << " " << x[i];
 53    std::cout << std::endl;
 54    std::cout << std::resetiosflags(fmt);
 55    if(rinfo[0] < 1.0e-12) // check for premature stop
 56        return 1; // request to interrupt
 57    return 0;
 58}
 59
 60int main()
 61{
 62    // CSR symmetric matrix. Only the lower triangle is stored
 63    std::vector<aoclsparse_int> icrow, icol;
 64    std::vector<double>         aval;
 65    aoclsparse_int              n = 8, nnz = 18;
 66    icrow.assign({0, 1, 2, 5, 6, 8, 11, 15, 18});
 67    icol.assign({0, 1, 0, 1, 2, 3, 1, 4, 0, 4, 5, 0, 3, 4, 6, 2, 5, 7});
 68    aval.assign({19, 10, 1, 8, 11, 13, 2, 11, 2, 1, 9, 7, 9, 5, 12, 5, 5, 9});
 69
 70    // Create aocl sparse matrix
 71    aoclsparse_matrix     A;
 72    aoclsparse_index_base base = aoclsparse_index_base_zero;
 73    aoclsparse_mat_descr  descr_a;
 74    aoclsparse_operation  trans = aoclsparse_operation_none;
 75    aoclsparse_create_dcsr(&A, base, n, n, nnz, icrow.data(), icol.data(), aval.data());
 76    aoclsparse_create_mat_descr(&descr_a);
 77    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
 78    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
 79    aoclsparse_set_mat_index_base(descr_a, base);
 80    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
 81    aoclsparse_optimize(A);
 82
 83    // Initialize initial point x0 and right hand side b
 84    std::vector<double> x, b, expected_sol, y;
 85    x.assign({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
 86    b.assign({0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0});
 87    expected_sol.assign({1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0});
 88    double alpha = 1.0, beta = 0.;
 89    y.resize(n);
 90    aoclsparse_dmv(trans, &alpha, A, descr_a, expected_sol.data(), &beta, b.data());
 91
 92    // create CG handle
 93    aoclsparse_itsol_handle handle = nullptr;
 94    aoclsparse_itsol_d_init(&handle);
 95
 96    if(aoclsparse_itsol_option_set(handle, "CG Abs Tolerance", "5.0e-6")
 97           != aoclsparse_status_success
 98       || aoclsparse_itsol_option_set(handle, "CG Preconditioner", "SGS")
 99              != aoclsparse_status_success)
100        std::cout << "Warning an option could not be set" << std::endl;
101
102    // Call CG solver
103    aoclsparse_status status;
104    double            rinfo[100];
105    status = aoclsparse_itsol_d_solve(
106        handle, n, A, descr_a, b.data(), x.data(), rinfo, nullptr, monit, &n);
107    if(status == aoclsparse_status_success)
108    {
109        std::cout.precision(2);
110        std::cout << std::scientific;
111        aoclsparse_itsol_handle_prn_options(handle);
112        std::cout << std::endl
113                  << "Solution found: (residual = " << rinfo[0] << " in " << (int)rinfo[30]
114                  << " iterations)" << std::endl
115                  << "   Final X* = ";
116        for(int i = 0; i < n; i++)
117            std::cout << std::setw(9) << x[i] << " ";
118        std::cout << std::endl;
119        std::cout << "Expected X* = ";
120        for(int i = 0; i < n; i++)
121            std::cout << std::setw(9) << expected_sol[i] << " ";
122        std::cout << std::endl;
123    }
124    else if(status == aoclsparse_status_user_stop)
125    {
126        std::cout << "User requested to terminate at interation " << (aoclsparse_int)rinfo[30]
127                  << std::endl;
128    }
129    else
130        std::cout << "Something unexpected happened. Status = " << status << std::endl;
131
132    aoclsparse_itsol_destroy(&handle);
133    aoclsparse_destroy_mat_descr(descr_a);
134    aoclsparse_destroy(&A);
135
136    return 0;
137}

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <cfloat>
 27#include <iomanip>
 28#include <iostream>
 29#include <math.h>
 30#include <vector>
 31
 32#define PREMATURE_STOP_TOLERANCE 1e-4
 33const char gmres_sol[] = "gmres_direct_d";
 34
 35double calculate_l2Norm_solvers(const double *xSol, const double *x, aoclsparse_int n)
 36{
 37    double norm = 0.0f;
 38    //residual = xSol - x
 39    //xSol obtained by initial spmv
 40    //x obtained by ILU-GMRES iterations
 41    for(aoclsparse_int i = 0; i < n; i++)
 42    {
 43        double a = xSol[i] - x[i];
 44        norm += a * a;
 45    }
 46    norm = sqrt(norm);
 47    return norm;
 48}
 49
 50aoclsparse_int monit(aoclsparse_int n,
 51                     const double  *x,
 52                     const double  *r __attribute__((unused)),
 53                     double        *rinfo,
 54                     void          *udata __attribute__((unused)))
 55{
 56    int    it  = (int)rinfo[30];
 57    double tol = PREMATURE_STOP_TOLERANCE;
 58
 59    std::ios oldState(nullptr);
 60    oldState.copyfmt(std::cout);
 61
 62    std::ios_base::fmtflags fmt = std::cout.flags();
 63    fmt |= std::ios_base::scientific | std::ios_base::right | std::ios_base::showpos;
 64
 65    if(!(it % 10))
 66    {
 67        std::cout << std::setw(5) << std::right << " iter"
 68                  << " " << std::setw(16) << std::right << "optim";
 69        for(int i = 0; i < n; i++)
 70            std::cout << std::setw(8) << std::right << "x[" << i << "]";
 71        std::cout << std::endl;
 72    }
 73    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 74              << std::scientific << std::setprecision(8) << rinfo[0];
 75    std::cout << std::setprecision(2) << std::showpos;
 76    for(int i = 0; i < n; i++)
 77        std::cout << " " << x[i];
 78    std::cout << std::endl;
 79    std::cout << std::resetiosflags(fmt);
 80
 81    //reset std::cout state
 82    std::cout.copyfmt(oldState);
 83
 84    if(rinfo[0] < tol) // check for premature stop
 85    {
 86        return 1; // request to interrupt
 87    }
 88    return 0;
 89}
 90
 91int main()
 92{
 93    std::vector<aoclsparse_int> csr_row_ptr;
 94    std::vector<aoclsparse_int> csr_col_ind;
 95    std::vector<double>         csr_val;
 96
 97    int               m, n, nnz;
 98    aoclsparse_status exit_status = aoclsparse_status_success;
 99
100    std::string filename = "cage4.mtx";
101    //symmetry = 0; //real unsymmetric, symmetry = 0%, spd = no
102    //https://www.cise.ufl.edu/research/sparse/MM/vanHeukelum/cage4.tar.gz
103    n   = 9;
104    m   = 9;
105    nnz = 49;
106    csr_row_ptr.assign({0, 5, 10, 15, 20, 26, 32, 38, 44, 49});
107    csr_col_ind.assign({0, 1, 3, 4, 7, 0, 1, 2, 4, 5, 1, 2, 3, 5, 6, 0, 2, 3, 6, 7, 0, 1, 4, 5, 6,
108                        8, 1, 2, 4, 5, 7, 8, 2, 3, 4, 6, 7, 8, 0, 3, 5, 6, 7, 8, 4, 5, 6, 7, 8});
109    csr_val.assign({0.75, 0.14, 0.11, 0.14, 0.11, 0.08, 0.69, 0.11, 0.08, 0.11, 0.09, 0.67, 0.08,
110                    0.09, 0.08, 0.09, 0.14, 0.73, 0.14, 0.09, 0.04, 0.04, 0.54, 0.14, 0.11, 0.25,
111                    0.05, 0.05, 0.08, 0.45, 0.08, 0.15, 0.04, 0.04, 0.09, 0.47, 0.09, 0.18, 0.05,
112                    0.05, 0.14, 0.11, 0.55, 0.25, 0.08, 0.08, 0.09, 0.08, 0.17});
113
114    // Create aocl sparse matrix
115    aoclsparse_matrix     A;
116    aoclsparse_index_base base = aoclsparse_index_base_zero;
117    aoclsparse_mat_descr  descr_a;
118    aoclsparse_operation  trans = aoclsparse_operation_none;
119    aoclsparse_create_dcsr(&A,
120                           base,
121                           (aoclsparse_int)n,
122                           (aoclsparse_int)n,
123                           (aoclsparse_int)nnz,
124                           csr_row_ptr.data(),
125                           csr_col_ind.data(),
126                           csr_val.data());
127    aoclsparse_create_mat_descr(&descr_a);
128    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
129    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
130    aoclsparse_set_mat_index_base(descr_a, base);
131    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
132    aoclsparse_optimize(A);
133
134    // Initialize initial point x0 and right hand side b
135    double *expected_sol = NULL;
136    double *x            = NULL;
137    double *b            = NULL;
138    double  norm         = 0.0;
139    double  rinfo[100];
140    double  alpha = 1.0, beta = 0.;
141    int     rs_iters = 7;
142    char    rs_iters_string[16];
143
144    expected_sol = new double[n];
145    x            = new double[n];
146    b            = new double[n];
147
148    double init_x = 1.0, ref_x = 0.5;
149    for(int i = 0; i < n; i++)
150    {
151        expected_sol[i] = ref_x;
152        x[i]            = init_x;
153    }
154
155    aoclsparse_dmv(trans, &alpha, A, descr_a, expected_sol, &beta, b);
156
157    double                  tol    = PREMATURE_STOP_TOLERANCE;
158    aoclsparse_itsol_handle handle = NULL;
159    // create GMRES handle
160    aoclsparse_itsol_d_init(&handle);
161
162    exit_status = aoclsparse_itsol_option_set(handle, "iterative method", "GMRES");
163    if(exit_status != aoclsparse_status_success)
164        printf("Warning an iterative method option could not be set, exit status = %d\n",
165               exit_status);
166
167    exit_status = aoclsparse_itsol_option_set(handle, "gmres preconditioner", "ILU0");
168    if(exit_status != aoclsparse_status_success)
169        printf("Warning gmres preconditioner option could not be set, exit status = %d\n",
170               exit_status);
171
172    exit_status = aoclsparse_itsol_option_set(handle, "gmres iteration limit", "50");
173    if(exit_status != aoclsparse_status_success)
174        printf("Warning gmres iteration limit option could not be set, exit status = %d\n",
175               exit_status);
176
177    sprintf(rs_iters_string, "%d", (int)rs_iters);
178    exit_status = aoclsparse_itsol_option_set(handle, "gmres restart iterations", rs_iters_string);
179    if(exit_status != aoclsparse_status_success)
180        printf("Warning gmres restart iterations option could not be set, exit status = %d\n",
181               exit_status);
182
183    aoclsparse_itsol_handle_prn_options(handle);
184
185    // Call GMRES solver
186    aoclsparse_status status;
187
188    status = aoclsparse_itsol_d_solve(handle, n, A, descr_a, b, x, rinfo, NULL, monit, &n);
189    if(status == aoclsparse_status_success || status == aoclsparse_status_user_stop
190       || aoclsparse_status_maxit == status)
191    {
192        norm = calculate_l2Norm_solvers(expected_sol, x, n);
193        printf("input = %s\n", filename.c_str());
194        printf("solver = %s\n", gmres_sol);
195        printf("no of rows = %d\n", (int)m);
196        printf("no of cols = %d\n", (int)n);
197        printf("no of nnz = %d\n", (int)nnz);
198        printf("monitoring tolerance = %e\n", tol);
199        printf("restart iterations = %d\n", (int)rs_iters);
200        printf("residual achieved = %e\n", rinfo[0]);
201        printf("total iterations = %d\n", (int)rinfo[30]);
202        printf("l2 Norm = %e\n", norm);
203    }
204    else
205    {
206        std::cout << "Something unexpected happened!, Status = " << status << std::endl;
207    }
208
209    delete[] expected_sol;
210    delete[] x;
211    delete[] b;
212    aoclsparse_itsol_destroy(&handle);
213    aoclsparse_destroy_mat_descr(descr_a);
214    aoclsparse_destroy(&A);
215    printf("\n");
216    fflush(stdout);
217
218    return 0;
219}

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <iomanip>
 27#include <iostream>
 28#include <math.h>
 29#include <vector>
 30
 31aoclsparse_int monit(aoclsparse_int n,
 32                     const float   *x,
 33                     const float   *r __attribute__((unused)),
 34                     float         *rinfo,
 35                     void          *udata __attribute__((unused)))
 36{
 37    int                     it  = (int)rinfo[30];
 38    std::ios_base::fmtflags fmt = std::cout.flags();
 39    fmt |= std::ios_base::scientific | std::ios_base::right | std::ios_base::showpos;
 40    if(!(it % 10))
 41    {
 42        std::cout << std::setw(5) << std::right << " iter"
 43                  << " " << std::setw(16) << std::right << "residual norm2";
 44        for(int i = 0; i < n; i++)
 45            std::cout << std::setw(8) << std::right << "x[" << i << "]";
 46        std::cout << std::endl;
 47    }
 48    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 49              << std::scientific << std::setprecision(8) << rinfo[0];
 50    std::cout << std::setprecision(2) << std::showpos;
 51    for(int i = 0; i < n; i++)
 52        std::cout << " " << x[i];
 53    std::cout << std::endl;
 54    std::cout << std::resetiosflags(fmt);
 55    if(rinfo[0] < 1.0e-12) // check for premature stop
 56        return 1; // request to interrupt
 57    return 0;
 58}
 59
 60int main()
 61{
 62    // CSR symmetric matrix. Only the lower triangle is stored
 63    std::vector<aoclsparse_int> icrow, icol;
 64    std::vector<float>          aval;
 65    aoclsparse_int              n = 8, nnz = 18;
 66    icrow.assign({0, 1, 2, 5, 6, 8, 11, 15, 18});
 67    icol.assign({0, 1, 0, 1, 2, 3, 1, 4, 0, 4, 5, 0, 3, 4, 6, 2, 5, 7});
 68    aval.assign({19, 10, 1, 8, 11, 13, 2, 11, 2, 1, 9, 7, 9, 5, 12, 5, 5, 9});
 69
 70    // Create aocl sparse matrix
 71    aoclsparse_matrix     A;
 72    aoclsparse_index_base base = aoclsparse_index_base_zero;
 73    aoclsparse_mat_descr  descr_a;
 74    aoclsparse_operation  trans = aoclsparse_operation_none;
 75    aoclsparse_create_scsr(&A, base, n, n, nnz, icrow.data(), icol.data(), aval.data());
 76    aoclsparse_create_mat_descr(&descr_a);
 77    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
 78    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
 79    aoclsparse_set_mat_index_base(descr_a, base);
 80    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
 81    aoclsparse_optimize(A);
 82
 83    // Initialize initial point x0 and right hand side b
 84    std::vector<float> x, b, expected_sol, y;
 85    x.assign({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
 86    b.assign({0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0});
 87    expected_sol.assign({1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0});
 88    float alpha = 1.0, beta = 0.;
 89    y.resize(n);
 90    aoclsparse_smv(trans, &alpha, A, descr_a, expected_sol.data(), &beta, b.data());
 91
 92    // create CG handle
 93    aoclsparse_itsol_handle handle = nullptr;
 94    aoclsparse_itsol_s_init(&handle);
 95
 96    if(aoclsparse_itsol_option_set(handle, "CG Rel Tolerance", "1.0e-06")
 97           != aoclsparse_status_success
 98       || aoclsparse_itsol_option_set(handle, "CG Preconditioner", "SGS")
 99              != aoclsparse_status_success)
100        std::cout << "Warning an option could not be set" << std::endl;
101
102    // Call CG solver
103    aoclsparse_status status;
104    float             rinfo[100];
105    status = aoclsparse_itsol_s_solve(
106        handle, n, A, descr_a, b.data(), x.data(), rinfo, nullptr, monit, &n);
107    if(status == aoclsparse_status_success)
108    {
109        std::cout.precision(2);
110        std::cout << std::scientific;
111        aoclsparse_itsol_handle_prn_options(handle);
112        std::cout << std::endl
113                  << "Solution found: (residual = " << rinfo[0] << " in " << (int)rinfo[30]
114                  << " iterations)" << std::endl
115                  << "   Final X* = ";
116        for(int i = 0; i < n; i++)
117            std::cout << std::setw(9) << x[i] << " ";
118        std::cout << std::endl;
119        std::cout << "Expected X* = ";
120        for(int i = 0; i < n; i++)
121            std::cout << std::setw(9) << expected_sol[i] << " ";
122        std::cout << std::endl;
123    }
124    else
125        std::cout << "Something unexpected happened " << status << std::endl;
126
127    aoclsparse_itsol_destroy(&handle);
128    aoclsparse_destroy_mat_descr(descr_a);
129    aoclsparse_destroy(&A);
130
131    return 0;
132}

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <cfloat>
 27#include <iomanip>
 28#include <iostream>
 29#include <math.h>
 30#include <vector>
 31
 32#define PREMATURE_STOP_TOLERANCE 1e-4
 33const char gmres_sol[] = "gmres_direct_s";
 34
 35float calculate_l2Norm_solvers(const float *xSol, const float *x, aoclsparse_int n)
 36{
 37    float norm = 0.0f;
 38    //residual = xSol - x
 39    //xSol obtained by initial spmv
 40    //x obtained by ILU-GMRES iterations
 41    for(aoclsparse_int i = 0; i < n; i++)
 42    {
 43        float a = xSol[i] - x[i];
 44        norm += a * a;
 45    }
 46    norm = sqrt(norm);
 47    return norm;
 48}
 49
 50aoclsparse_int monit(aoclsparse_int n,
 51                     const float   *x,
 52                     const float   *r __attribute__((unused)),
 53                     float         *rinfo,
 54                     void          *udata __attribute__((unused)))
 55{
 56    int   it  = (int)rinfo[30];
 57    float tol = PREMATURE_STOP_TOLERANCE;
 58
 59    std::ios oldState(nullptr);
 60    oldState.copyfmt(std::cout);
 61
 62    std::ios_base::fmtflags fmt = std::cout.flags();
 63    fmt |= std::ios_base::scientific | std::ios_base::right | std::ios_base::showpos;
 64
 65    if(!(it % 10))
 66    {
 67        std::cout << std::setw(5) << std::right << " iter"
 68                  << " " << std::setw(16) << std::right << "optim";
 69        for(int i = 0; i < n; i++)
 70            std::cout << std::setw(8) << std::right << "x[" << i << "]";
 71        std::cout << std::endl;
 72    }
 73    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 74              << std::scientific << std::setprecision(8) << rinfo[0];
 75    std::cout << std::setprecision(2) << std::showpos;
 76    for(int i = 0; i < n; i++)
 77        std::cout << " " << x[i];
 78    std::cout << std::endl;
 79    std::cout << std::resetiosflags(fmt);
 80
 81    //reset std::cout state
 82    std::cout.copyfmt(oldState);
 83
 84    if(rinfo[0] < tol) // check for premature stop
 85    {
 86        return 1; // request to interrupt
 87    }
 88    return 0;
 89}
 90
 91int main()
 92{
 93    // CSR symmetric matrix. Only the lower triangle is stored
 94    std::vector<aoclsparse_int> csr_row_ptr;
 95    std::vector<aoclsparse_int> csr_col_ind;
 96    std::vector<float>          csr_val;
 97
 98    int               m, n, nnz;
 99    aoclsparse_status exit_status = aoclsparse_status_success;
100
101    std::string filename = "cage4.mtx";
102    //symmetry = 0; //real unsymmetric, symmetry = 0%, spd = no
103    //https://www.cise.ufl.edu/research/sparse/MM/vanHeukelum/cage4.tar.gz
104    n   = 9;
105    m   = 9;
106    nnz = 49;
107    csr_row_ptr.assign({0, 5, 10, 15, 20, 26, 32, 38, 44, 49});
108    csr_col_ind.assign({0, 1, 3, 4, 7, 0, 1, 2, 4, 5, 1, 2, 3, 5, 6, 0, 2, 3, 6, 7, 0, 1, 4, 5, 6,
109                        8, 1, 2, 4, 5, 7, 8, 2, 3, 4, 6, 7, 8, 0, 3, 5, 6, 7, 8, 4, 5, 6, 7, 8});
110    csr_val.assign({0.75, 0.14, 0.11, 0.14, 0.11, 0.08, 0.69, 0.11, 0.08, 0.11, 0.09, 0.67, 0.08,
111                    0.09, 0.08, 0.09, 0.14, 0.73, 0.14, 0.09, 0.04, 0.04, 0.54, 0.14, 0.11, 0.25,
112                    0.05, 0.05, 0.08, 0.45, 0.08, 0.15, 0.04, 0.04, 0.09, 0.47, 0.09, 0.18, 0.05,
113                    0.05, 0.14, 0.11, 0.55, 0.25, 0.08, 0.08, 0.09, 0.08, 0.17});
114
115    // Create aocl sparse matrix
116    aoclsparse_matrix     A;
117    aoclsparse_index_base base = aoclsparse_index_base_zero;
118    aoclsparse_mat_descr  descr_a;
119    aoclsparse_operation  trans = aoclsparse_operation_none;
120    aoclsparse_create_scsr(&A,
121                           base,
122                           (aoclsparse_int)n,
123                           (aoclsparse_int)n,
124                           (aoclsparse_int)nnz,
125                           csr_row_ptr.data(),
126                           csr_col_ind.data(),
127                           csr_val.data());
128    aoclsparse_create_mat_descr(&descr_a);
129    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
130    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
131    aoclsparse_set_mat_index_base(descr_a, base);
132    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
133    aoclsparse_optimize(A);
134
135    // Initialize initial point x0 and right hand side b
136    float *expected_sol = NULL;
137    float *x            = NULL;
138    float *b            = NULL;
139    float  norm         = 0.0;
140    float  rinfo[100];
141    float  alpha = 1.0, beta = 0.;
142    int    rs_iters = 7;
143    char   rs_iters_string[16];
144
145    expected_sol = new float[n];
146    x            = new float[n];
147    b            = new float[n];
148
149    float init_x = 1.0, ref_x = 0.5;
150    for(int i = 0; i < n; i++)
151    {
152        expected_sol[i] = ref_x;
153        x[i]            = init_x;
154    }
155
156    // generate RHS
157    // Reference SPMV CSR implementation
158    aoclsparse_smv(trans, &alpha, A, descr_a, expected_sol, &beta, b);
159
160    float                   tol    = PREMATURE_STOP_TOLERANCE;
161    aoclsparse_itsol_handle handle = nullptr;
162    // create GMRES handle
163    aoclsparse_itsol_s_init(&handle);
164
165    exit_status = aoclsparse_itsol_option_set(handle, "iterative method", "GMRES");
166    if(exit_status != aoclsparse_status_success)
167        printf("Warning an iterative method option could not be set, exit status = %d\n",
168               exit_status);
169
170    exit_status = aoclsparse_itsol_option_set(handle, "gmres preconditioner", "ILU0");
171    if(exit_status != aoclsparse_status_success)
172        printf("Warning gmres preconditioner option could not be set, exit status = %d\n",
173               exit_status);
174
175    exit_status = aoclsparse_itsol_option_set(handle, "gmres iteration limit", "50");
176    if(exit_status != aoclsparse_status_success)
177        printf("Warning gmres iteration limit option could not be set, exit status = %d\n",
178               exit_status);
179
180    sprintf(rs_iters_string, "%d", (int)rs_iters);
181    exit_status = aoclsparse_itsol_option_set(handle, "gmres restart iterations", rs_iters_string);
182    if(exit_status != aoclsparse_status_success)
183        printf("Warning gmres restart iterations option could not be set, exit status = %d\n",
184               exit_status);
185
186    aoclsparse_itsol_handle_prn_options(handle);
187
188    // Call GMRES solver
189    aoclsparse_status status;
190
191    status = aoclsparse_itsol_s_solve(handle, n, A, descr_a, b, x, rinfo, nullptr, monit, &n);
192    if(status == aoclsparse_status_success || status == aoclsparse_status_user_stop
193       || aoclsparse_status_maxit == status)
194    {
195        norm = calculate_l2Norm_solvers(expected_sol, x, n);
196
197        printf("input = %s\n", filename.c_str());
198        printf("solver = %s\n", gmres_sol);
199        printf("no of rows = %d\n", (int)m);
200        printf("no of cols = %d\n", (int)n);
201        printf("no of nnz = %d\n", (int)nnz);
202        printf("monitoring tolerance = %e\n", tol);
203        printf("restart iterations = %d\n", (int)rs_iters);
204        printf("residual achieved = %e\n", rinfo[0]);
205        printf("total iterations = %d\n", (int)rinfo[30]);
206        printf("l2 Norm = %e\n", norm);
207    }
208    else
209    {
210        std::cout << "Something unexpected happened!, Status = " << status << std::endl;
211    }
212
213    delete[] expected_sol;
214    delete[] x;
215    delete[] b;
216    aoclsparse_destroy_mat_descr(descr_a);
217    aoclsparse_destroy(&A);
218    aoclsparse_itsol_destroy(&handle);
219    printf("\n");
220    fflush(stdout);
221
222    return 0;
223}
Parameters
  • handle[inout] a valid problem handle, previously initialized by calling aoclsparse_itsol_s_init or aoclsparse_itsol_d_init.

  • n[in] the size of the square matrix mat.

  • mat[inout] coefficient matrix \(A\).

  • descr[inout] matrix descriptor for mat.

  • b[in] right-hand side dense vector \(b\).

  • x[inout] dense vector of unknowns. On input, it should contain the initial guess from which to start the iterative process. If there is no good initial estimate guess then any arbitrary but finite values can be used. On output, it contains an estimate to the solution of the linear system of equations up to the requested tolerance, e.g. see “cg rel tolerance” or “cg abs tolerance” in Options.

  • rinfo[out] vector containing information and stats related to the iterative solve, see Information Array.

  • precond[in] (optional, can be nullptr) function pointer to a user routine that applies the preconditioning step

    \[ v = Mu \text{or } v = M^{-1}u,\]
    where \(v\) is the resulting vector of applying a preconditioning step on the vector \(u\) and \(M\) refers to the user specified preconditioner in matrix form and need not be explicitly available. The void pointer udata, is a convenience pointer that can be used by the user to point to user data and is not used by the itsol framework. If the user requests to use a predefined preconditioner already available in the suite (refer to e.g. “cg preconditioner” or “gmres preconditioner” in Options), then this parameter need not be provided.
  • monit[in] (optional, can be nullptr) function pointer to a user monitoring routine. If provided, then at each iteration, the routine is called and can be used to define a custom stopping criteria or to oversee the convergence process. In general, this function need not be provided. If provided then the solver provides n the problem size, x the current iterate, r the current residual vector ( \(r = Ax-b\)), rinfo the current solver’s stats, see Information Array, and udata a convenience pointer that can be used by the user to point to arbitrary user data and is not used by the itsol framework.

  • udata[inout] (optional, can be nullptr) user convenience pointer, it can be used by the user to pass a pointer to user data. It is not modified by the solver.

aoclsparse_itsol_option_set()#

aoclsparse_status aoclsparse_itsol_option_set(aoclsparse_itsol_handle handle, const char *option, const char *value)#

Option Setter.

This function sets the value to a given option inside the provided problem handle. Handle options can be printed using aoclsparse_itsol_handle_prn_options. Available options are listed in Options.

Options#

The iterative solver framework has the following options.

Option name

Type

Default

Description

Constraints

cg iteration limit

integer

\(i = 500\)

Set CG iteration limit

\(1 \le i\).

gmres iteration limit

integer

\(i = 150\)

Set GMRES iteration limit

\(1 \le i\).

gmres restart iterations

integer

\(i = 20\)

Set GMRES restart iterations

\(1 \le i\).

cg rel tolerance

real

\(r = 1.08735e-06\)

Set relative convergence tolerance for cg method

\(0 \le r\).

cg abs tolerance

real

\(r = 0\)

Set absolute convergence tolerance for cg method

\(0 \le r\).

gmres rel tolerance

real

\(r = 1.08735e-06\)

Set relative convergence tolerance for gmres method

\(0 \le r\).

gmres abs tolerance

real

\(r = 1e-06\)

Set absolute convergence tolerance for gmres method

\(0 \le r\).

iterative method

string

\(s = cg\)

Choose solver to use

\(s =\) cg, gm res, gmres, or pcg.

cg preconditioner

string

\(s = none\)

Choose preconditioner to use with cg method

\(s =\) gs, none, sgs, symgs, or user.

gmres preconditioner

string

\(s = none\)

Choose preconditioner to use with gmres method

\(s =\) ilu0, none, or user.

Note

It is worth noting that only some options apply to each specific solver, e.g. name of options that begin with “cg” affect the behaviour of the CG solver.

Parameters
  • handle[inout] pointer to the iterative solvers’ data structure.

  • option[in] string specifying the name of the option to set.

  • value[in] string providing the value to set the option to.

Return values
  • aoclsparse_status_success – the operation completed successfully.

  • aoclsparse_status_invalid_value – either the option name was not found or the provided option value is out of the valid range.

  • aoclsparse_status_invalid_pointer – the pointer to the problem handle is invalid.

  • aoclsparse_status_internal_error – an unexpected error occurred.

aoclsparse_itsol_handle_prn_options()#

void aoclsparse_itsol_handle_prn_options(aoclsparse_itsol_handle handle)#

Print options stored in a problem handle.

This function prints to the standard output a list of available options stored in a problem handle and their current value. For available options, see Options in aoclsparse_itsol_option_set.

Parameters

handle[in] pointer to the iterative solvers’ data structure.

aoclsparse_itsol_?_rci_input()#

aoclsparse_status aoclsparse_itsol_s_rci_input(aoclsparse_itsol_handle handle, aoclsparse_int n, const float *b)#
aoclsparse_status aoclsparse_itsol_d_rci_input(aoclsparse_itsol_handle handle, aoclsparse_int n, const double *b)#

Store partial data of the linear system of equations into the problem handle.

This function needs to be called before the reverse communication interface iterative solver is called. It registers the linear system’s dimension n, and stores the right-hand side vector b.

Note

This function does not need to be called if the forward communication interface is used.

Parameters
  • handle[inout] problem handle. Needs to be initialized by calling aoclsparse_itsol_s_init or aoclsparse_itsol_d_init.

  • n[in] the number of columns of the (square) linear system matrix.

  • b[in] the right hand side of the linear system. Must be a vector of size n.

Return values
  • aoclsparse_status_success – initialization completed successfully.

  • aoclsparse_status_invalid_pointer – one or more of the pointers handle, and b are invalid.

  • aoclsparse_status_wrong_typehandle was initialized with a different floating point precision than requested here, e.g. aoclsparse_itsol_d_init (double precision) was used to initialize handle but aoclsparse_itsol_s_rci_input (single precision) is being called instead of the correct double precision one, aoclsparse_itsol_d_rci_input.

  • aoclsparse_status_invalid_valuen was set to a negative value.

  • aoclsparse_status_memory_error – internal memory allocation error.

aoclsparse_itsol_?_rci_solve()#

aoclsparse_status aoclsparse_itsol_s_rci_solve(aoclsparse_itsol_handle handle, aoclsparse_itsol_rci_job *ircomm, float **u, float **v, float *x, float rinfo[100])#
aoclsparse_status aoclsparse_itsol_d_rci_solve(aoclsparse_itsol_handle handle, aoclsparse_itsol_rci_job *ircomm, double **u, double **v, double *x, double rinfo[100])#

Reverse Communication Interface (RCI) to the iterative solvers (itsol) suite.

This function solves the linear system of equations

\[ Ax=b, \]
where the matrix of coefficients \(A\) is not required to be provided explicitly. The right hand-side is the dense vector b and the vector of unknowns is x. If \(A\) is symmetric and positive definite then set the option “iterative method” to “cg” to solve the problem using the Conjugate Gradient method, alternatively set the option to “gmres” to solve using GMRes. See the Options for a list of available options to modify the behaviour of each solver.

The reverse communication interface (RCI), also know as _matrix-free_ interface does not require the user to explicitly provide the matrix \(A\). During the solve process whenever the algorithm requires a matrix operation (matrix-vector or transposed matrix-vector products), it returns control to the user with a flag ircomm indicating what operation is requested. Once the user performs the requested task it must call this function again to resume the solve.

The expected workflow is as follows:

  1. Call aoclsparse_itsol_s_init or aoclsparse_itsol_d_init to initialize the problem handle ( aoclsparse_itsol_handle)

  2. Choose the solver and adjust its behaviour by setting optional parameters with aoclsparse_itsol_option_set, see also Options.

  3. Define the problem size and right-hand side vector \(b\) with aoclsparse_itsol_d_rci_input.

  4. Solve the system with either aoclsparse_itsol_s_rci_solve or aoclsparse_itsol_d_rci_solve.

  5. If there is another linear system of equations to solve with the same matrix but a different right-hand side \(b\), then repeat from step 3.

  6. If solver terminated successfully then vector x contains the solution.

  7. Free the memory with aoclsparse_itsol_destroy.

These reverse communication interfaces complement the _forward communication_ interfaces aoclsparse_itsol_d_rci_solve and aoclsparse_itsol_s_rci_solve.

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <iomanip>
 27#include <iostream>
 28#include <math.h>
 29#include <vector>
 30
 31// Define custom log printer
 32void printer(double rinfo[100], bool header)
 33{
 34    std::ios_base::fmtflags fmt = std::cout.flags();
 35    fmt |= std::cout.scientific | std::cout.right;
 36    if(header)
 37        std::cout << std::setw(5) << std::right << " iter"
 38                  << " " << std::setw(16) << std::right << "optim"
 39                  << "  " << std::setw(3) << std::endl;
 40    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 41              << std::scientific << rinfo[0] << "  " << std::endl;
 42    std::resetiosflags(fmt);
 43}
 44
 45int main()
 46{
 47    // CSR symmetric matrix. Only the lower triangle is stored
 48    std::vector<aoclsparse_int> icrow, icol;
 49    std::vector<double>         aval;
 50    aoclsparse_int              n = 8, nnz = 18;
 51    icrow.assign({0, 1, 2, 5, 6, 8, 11, 15, 18});
 52    icol.assign({0, 1, 0, 1, 2, 3, 1, 4, 0, 4, 5, 0, 3, 4, 6, 2, 5, 7});
 53    aval.assign({19, 10, 1, 8, 11, 13, 2, 11, 2, 1, 9, 7, 9, 5, 12, 5, 5, 9});
 54
 55    // create matrix and its descriptor
 56    aoclsparse_matrix     A;
 57    aoclsparse_index_base base = aoclsparse_index_base_zero;
 58    aoclsparse_mat_descr  descr_a;
 59    aoclsparse_operation  trans = aoclsparse_operation_none;
 60    aoclsparse_create_dcsr(&A, base, n, n, nnz, icrow.data(), icol.data(), aval.data());
 61    aoclsparse_create_mat_descr(&descr_a);
 62    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
 63    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
 64    aoclsparse_set_mat_index_base(descr_a, base);
 65    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
 66    aoclsparse_optimize(A);
 67
 68    // Initialize initial point x0 and right hand side b
 69    std::vector<double> x, b, expected_sol, y;
 70    x.assign({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
 71    b.assign({0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0});
 72    expected_sol.assign({1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0});
 73    double alpha = 1.0, beta = 0.;
 74    y.resize(n);
 75    aoclsparse_dmv(trans, &alpha, A, descr_a, expected_sol.data(), &beta, b.data());
 76
 77    // create CG handle
 78    aoclsparse_itsol_handle handle = nullptr;
 79    aoclsparse_itsol_d_init(&handle);
 80
 81    // Change options, set user defined preconditioner
 82    if(aoclsparse_itsol_option_set(handle, "CG Iteration Limit", "50") != aoclsparse_status_success
 83       || aoclsparse_itsol_option_set(handle, "CG preconditioner", "user")
 84              != aoclsparse_status_success)
 85        std::cout << "Warning an option could not be set" << std::endl;
 86
 87    // initialize size and rhs inside the handle
 88    aoclsparse_itsol_d_rci_input(handle, n, b.data());
 89
 90    // Call CG solver
 91    aoclsparse_status        status;
 92    aoclsparse_itsol_rci_job ircomm = aoclsparse_rci_start;
 93    double                  *u      = nullptr;
 94    double                  *v      = nullptr;
 95    double                   rinfo[100];
 96    double                   tol = 1.0e-5;
 97    bool                     hdr;
 98    std::cout << std::endl;
 99    while(ircomm != aoclsparse_rci_stop)
100    {
101        status = aoclsparse_itsol_d_rci_solve(handle, &ircomm, &u, &v, x.data(), rinfo);
102        if(status != aoclsparse_status_success)
103            break;
104        switch(ircomm)
105        {
106        case aoclsparse_rci_mv:
107            // Compute v = Au
108            beta   = 0.0;
109            alpha  = 1.0;
110            status = aoclsparse_dmv(trans, &alpha, A, descr_a, u, &beta, v);
111            if(status != aoclsparse_status_success)
112                ircomm = aoclsparse_rci_stop;
113            break;
114
115        case aoclsparse_rci_precond:
116            // apply Symmetric Gauss-Seidel preconditioner step
117            status = aoclsparse_dtrsv(aoclsparse_operation_none, alpha, A, descr_a, u, y.data());
118            if(status != aoclsparse_status_success)
119            {
120                ircomm = aoclsparse_rci_stop;
121                break;
122            }
123            for(aoclsparse_int i = 0; i < n; i++)
124                y[i] *= aval[icrow[i + 1] - 1];
125            status
126                = aoclsparse_dtrsv(aoclsparse_operation_transpose, alpha, A, descr_a, y.data(), v);
127            if(status != aoclsparse_status_success)
128                ircomm = aoclsparse_rci_stop;
129            break;
130
131        case aoclsparse_rci_stopping_criterion:
132            // No operations required, can be used to monitor the progress of the solve
133            // or defining a custom stopping criterion
134            // print iteration log
135            hdr = ((int)rinfo[30] % 100) == 0;
136            printer(rinfo, hdr);
137            // request solver to stop if custom criterion is met
138            if(rinfo[0] < tol)
139            {
140                std::cout << "User stop. Final residual: " << rinfo[0] << std::endl;
141                ircomm = aoclsparse_rci_interrupt;
142            }
143            break;
144
145        default:
146            break;
147        }
148    }
149    // Print the final results if the internal stopping criterion or the user defined one were met
150    switch(status)
151    {
152    case aoclsparse_status_user_stop:
153    case aoclsparse_status_success:
154        std::cout.precision(2);
155        std::cout << std::scientific;
156        aoclsparse_itsol_handle_prn_options(handle);
157        std::cout << std::endl
158                  << "Solution found: (residual = " << rinfo[0] << " in " << (int)rinfo[30]
159                  << " iterations)" << std::endl
160                  << "   Final X* = ";
161        for(int i = 0; i < n; i++)
162            std::cout << std::setw(9) << x[i] << " ";
163        std::cout << std::endl;
164        std::cout << "Expected X* = ";
165        for(int i = 0; i < n; i++)
166            std::cout << std::setw(9) << expected_sol[i] << " ";
167        std::cout << std::endl;
168        break;
169
170    case aoclsparse_status_maxit:
171        std::cout << "solve stopped after " << (int)rinfo[30] << " iterations" << std::endl
172                  << "residual = " << rinfo[0] << std::endl;
173        break;
174
175    default:
176        std::cout << "Something unexpected happened! " << status << std::endl;
177    }
178    aoclsparse_itsol_destroy(&handle);
179    aoclsparse_destroy_mat_descr(descr_a);
180    aoclsparse_destroy(&A);
181
182    return 0;
183}

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <cfloat>
 27#include <iomanip>
 28#include <iostream>
 29#include <math.h>
 30#include <vector>
 31
 32#define PREMATURE_STOP_TOLERANCE 1e-4
 33const char gmres_sol[] = "gmres_direct_d";
 34
 35double calculate_l2Norm_solvers(const double *xSol, const double *x, aoclsparse_int n)
 36{
 37    double norm = 0.0f;
 38    //residual = xSol - x
 39    //xSol obtained by initial spmv
 40    //x obtained by ILU-GMRES iterations
 41    for(aoclsparse_int i = 0; i < n; i++)
 42    {
 43        double a = xSol[i] - x[i];
 44        norm += a * a;
 45    }
 46    norm = sqrt(norm);
 47    return norm;
 48}
 49
 50aoclsparse_int monit(aoclsparse_int n,
 51                     const double  *x,
 52                     const double  *r __attribute__((unused)),
 53                     double        *rinfo,
 54                     void          *udata __attribute__((unused)))
 55{
 56    int    it  = (int)rinfo[30];
 57    double tol = PREMATURE_STOP_TOLERANCE;
 58
 59    std::ios oldState(nullptr);
 60    oldState.copyfmt(std::cout);
 61
 62    std::ios_base::fmtflags fmt = std::cout.flags();
 63    fmt |= std::ios_base::scientific | std::ios_base::right | std::ios_base::showpos;
 64
 65    if(!(it % 10))
 66    {
 67        std::cout << std::setw(5) << std::right << " iter"
 68                  << " " << std::setw(16) << std::right << "optim";
 69        for(int i = 0; i < n; i++)
 70            std::cout << std::setw(8) << std::right << "x[" << i << "]";
 71        std::cout << std::endl;
 72    }
 73    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 74              << std::scientific << std::setprecision(8) << rinfo[0];
 75    std::cout << std::setprecision(2) << std::showpos;
 76    for(int i = 0; i < n; i++)
 77        std::cout << " " << x[i];
 78    std::cout << std::endl;
 79    std::cout << std::resetiosflags(fmt);
 80
 81    //reset std::cout state
 82    std::cout.copyfmt(oldState);
 83
 84    if(rinfo[0] < tol) // check for premature stop
 85    {
 86        return 1; // request to interrupt
 87    }
 88    return 0;
 89}
 90
 91int main()
 92{
 93    std::vector<aoclsparse_int> csr_row_ptr;
 94    std::vector<aoclsparse_int> csr_col_ind;
 95    std::vector<double>         csr_val;
 96
 97    int               m, n, nnz;
 98    aoclsparse_status exit_status = aoclsparse_status_success;
 99
100    std::string filename = "cage4.mtx";
101    //symmetry = 0; //real unsymmetric, symmetry = 0%, spd = no
102    //https://www.cise.ufl.edu/research/sparse/MM/vanHeukelum/cage4.tar.gz
103    n   = 9;
104    m   = 9;
105    nnz = 49;
106    csr_row_ptr.assign({0, 5, 10, 15, 20, 26, 32, 38, 44, 49});
107    csr_col_ind.assign({0, 1, 3, 4, 7, 0, 1, 2, 4, 5, 1, 2, 3, 5, 6, 0, 2, 3, 6, 7, 0, 1, 4, 5, 6,
108                        8, 1, 2, 4, 5, 7, 8, 2, 3, 4, 6, 7, 8, 0, 3, 5, 6, 7, 8, 4, 5, 6, 7, 8});
109    csr_val.assign({0.75, 0.14, 0.11, 0.14, 0.11, 0.08, 0.69, 0.11, 0.08, 0.11, 0.09, 0.67, 0.08,
110                    0.09, 0.08, 0.09, 0.14, 0.73, 0.14, 0.09, 0.04, 0.04, 0.54, 0.14, 0.11, 0.25,
111                    0.05, 0.05, 0.08, 0.45, 0.08, 0.15, 0.04, 0.04, 0.09, 0.47, 0.09, 0.18, 0.05,
112                    0.05, 0.14, 0.11, 0.55, 0.25, 0.08, 0.08, 0.09, 0.08, 0.17});
113
114    // Create aocl sparse matrix
115    aoclsparse_matrix     A;
116    aoclsparse_index_base base = aoclsparse_index_base_zero;
117    aoclsparse_mat_descr  descr_a;
118    aoclsparse_operation  trans = aoclsparse_operation_none;
119    aoclsparse_create_dcsr(&A,
120                           base,
121                           (aoclsparse_int)n,
122                           (aoclsparse_int)n,
123                           (aoclsparse_int)nnz,
124                           csr_row_ptr.data(),
125                           csr_col_ind.data(),
126                           csr_val.data());
127    aoclsparse_create_mat_descr(&descr_a);
128    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
129    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
130    aoclsparse_set_mat_index_base(descr_a, base);
131    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
132    aoclsparse_optimize(A);
133
134    // Initialize initial point x0 and right hand side b
135    double *expected_sol = NULL;
136    double *x            = NULL;
137    double *b            = NULL;
138    double  norm         = 0.0;
139    double  rinfo[100];
140    double  alpha = 1.0, beta = 0.;
141    int     rs_iters = 7;
142    char    rs_iters_string[16];
143
144    expected_sol = new double[n];
145    x            = new double[n];
146    b            = new double[n];
147
148    double init_x = 1.0, ref_x = 0.5;
149    for(int i = 0; i < n; i++)
150    {
151        expected_sol[i] = ref_x;
152        x[i]            = init_x;
153    }
154
155    aoclsparse_dmv(trans, &alpha, A, descr_a, expected_sol, &beta, b);
156
157    double                  tol    = PREMATURE_STOP_TOLERANCE;
158    aoclsparse_itsol_handle handle = NULL;
159    // create GMRES handle
160    aoclsparse_itsol_d_init(&handle);
161
162    exit_status = aoclsparse_itsol_option_set(handle, "iterative method", "GMRES");
163    if(exit_status != aoclsparse_status_success)
164        printf("Warning an iterative method option could not be set, exit status = %d\n",
165               exit_status);
166
167    exit_status = aoclsparse_itsol_option_set(handle, "gmres preconditioner", "ILU0");
168    if(exit_status != aoclsparse_status_success)
169        printf("Warning gmres preconditioner option could not be set, exit status = %d\n",
170               exit_status);
171
172    exit_status = aoclsparse_itsol_option_set(handle, "gmres iteration limit", "50");
173    if(exit_status != aoclsparse_status_success)
174        printf("Warning gmres iteration limit option could not be set, exit status = %d\n",
175               exit_status);
176
177    sprintf(rs_iters_string, "%d", (int)rs_iters);
178    exit_status = aoclsparse_itsol_option_set(handle, "gmres restart iterations", rs_iters_string);
179    if(exit_status != aoclsparse_status_success)
180        printf("Warning gmres restart iterations option could not be set, exit status = %d\n",
181               exit_status);
182
183    aoclsparse_itsol_handle_prn_options(handle);
184
185    // Call GMRES solver
186    aoclsparse_status status;
187
188    status = aoclsparse_itsol_d_solve(handle, n, A, descr_a, b, x, rinfo, NULL, monit, &n);
189    if(status == aoclsparse_status_success || status == aoclsparse_status_user_stop
190       || aoclsparse_status_maxit == status)
191    {
192        norm = calculate_l2Norm_solvers(expected_sol, x, n);
193        printf("input = %s\n", filename.c_str());
194        printf("solver = %s\n", gmres_sol);
195        printf("no of rows = %d\n", (int)m);
196        printf("no of cols = %d\n", (int)n);
197        printf("no of nnz = %d\n", (int)nnz);
198        printf("monitoring tolerance = %e\n", tol);
199        printf("restart iterations = %d\n", (int)rs_iters);
200        printf("residual achieved = %e\n", rinfo[0]);
201        printf("total iterations = %d\n", (int)rinfo[30]);
202        printf("l2 Norm = %e\n", norm);
203    }
204    else
205    {
206        std::cout << "Something unexpected happened!, Status = " << status << std::endl;
207    }
208
209    delete[] expected_sol;
210    delete[] x;
211    delete[] b;
212    aoclsparse_itsol_destroy(&handle);
213    aoclsparse_destroy_mat_descr(descr_a);
214    aoclsparse_destroy(&A);
215    printf("\n");
216    fflush(stdout);
217
218    return 0;
219}

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <iomanip>
 27#include <iostream>
 28#include <math.h>
 29#include <vector>
 30
 31// Define custom log printer
 32void printer(float rinfo[100], bool header)
 33{
 34    std::ios_base::fmtflags fmt = std::cout.flags();
 35    fmt |= std::cout.scientific | std::cout.right;
 36    if(header)
 37        std::cout << std::setw(5) << std::right << " iter"
 38                  << " " << std::setw(16) << std::right << "optim"
 39                  << "  " << std::setw(3) << std::endl;
 40    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 41              << std::scientific << rinfo[0] << "  " << std::endl;
 42    std::resetiosflags(fmt);
 43}
 44
 45int main()
 46{
 47    // CSR symmetric matrix. Only the lower triangle is stored
 48    std::vector<aoclsparse_int> icrow, icol;
 49    std::vector<float>          aval;
 50    aoclsparse_int              n = 8, nnz = 18;
 51    icrow.assign({0, 1, 2, 5, 6, 8, 11, 15, 18});
 52    icol.assign({0, 1, 0, 1, 2, 3, 1, 4, 0, 4, 5, 0, 3, 4, 6, 2, 5, 7});
 53    aval.assign({19, 10, 1, 8, 11, 13, 2, 11, 2, 1, 9, 7, 9, 5, 12, 5, 5, 9});
 54
 55    // Create aocl sparse matrix and its descriptor
 56    aoclsparse_matrix     A;
 57    aoclsparse_index_base base = aoclsparse_index_base_zero;
 58    aoclsparse_mat_descr  descr_a;
 59    aoclsparse_operation  trans = aoclsparse_operation_none;
 60    aoclsparse_create_scsr(&A, base, n, n, nnz, icrow.data(), icol.data(), aval.data());
 61    aoclsparse_create_mat_descr(&descr_a);
 62    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
 63    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
 64    aoclsparse_set_mat_index_base(descr_a, base);
 65    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
 66    aoclsparse_optimize(A);
 67
 68    // create CG handle
 69    aoclsparse_itsol_handle handle = nullptr;
 70    aoclsparse_itsol_s_init(&handle);
 71
 72    // Change options (update to use )
 73    if(aoclsparse_itsol_option_set(handle, "CG Rel Tolerance", "1.0e-06")
 74           != aoclsparse_status_success
 75       || aoclsparse_itsol_option_set(handle, "CG preconditioner", "user")
 76              != aoclsparse_status_success)
 77        std::cout << "Warning an option could not be set" << std::endl;
 78
 79    // Initialize initial point x0 and right hand side b
 80    std::vector<float> x, b, expected_sol, y;
 81    x.assign({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0});
 82    b.assign({0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0});
 83    expected_sol.assign({1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0, 1.E0, 0.E0});
 84    float alpha = 1.0, beta = 0.;
 85    y.resize(n);
 86    aoclsparse_smv(trans, &alpha, A, descr_a, expected_sol.data(), &beta, b.data());
 87
 88    // initialize size and rhs inside the handle
 89    aoclsparse_itsol_s_rci_input(handle, n, b.data());
 90
 91    // Call CG solver
 92    aoclsparse_itsol_rci_job ircomm = aoclsparse_rci_start;
 93    aoclsparse_status        status;
 94    float                   *u = nullptr;
 95    float                   *v = nullptr;
 96    float                    rinfo[100];
 97    float                    tol = 1.0e-5;
 98    bool                     hdr;
 99    std::cout << std::endl;
100    while(ircomm != aoclsparse_rci_stop)
101    {
102        status = aoclsparse_itsol_s_rci_solve(handle, &ircomm, &u, &v, x.data(), rinfo);
103        if(status != aoclsparse_status_success)
104            break;
105        switch(ircomm)
106        {
107        case aoclsparse_rci_mv:
108            // Compute v = Au
109            beta   = 0.0;
110            alpha  = 1.0;
111            status = aoclsparse_smv(trans, &alpha, A, descr_a, u, &beta, v);
112            if(status != aoclsparse_status_success)
113                ircomm = aoclsparse_rci_stop;
114            break;
115
116        case aoclsparse_rci_precond:
117            // apply Symmetric Gauss-Seidel preconditioner step
118            status = aoclsparse_strsv(aoclsparse_operation_none, alpha, A, descr_a, u, y.data());
119            if(status != aoclsparse_status_success)
120            {
121                ircomm = aoclsparse_rci_stop;
122                break;
123            }
124            for(aoclsparse_int i = 0; i < n; i++)
125                y[i] *= aval[icrow[i + 1] - 1];
126            status
127                = aoclsparse_strsv(aoclsparse_operation_transpose, alpha, A, descr_a, y.data(), v);
128            if(status != aoclsparse_status_success)
129                ircomm = aoclsparse_rci_stop;
130            break;
131
132        case aoclsparse_rci_stopping_criterion:
133            // No operations required, can be used to monitor the progress of the solve
134            // or defining a custom stopping criterion
135            // print iteration log
136            hdr = ((int)rinfo[30] % 100) == 0;
137            printer(rinfo, hdr);
138            // request solver to stop if custom criterion is met
139            if(rinfo[0] < tol)
140            {
141                std::cout << "User stop. Final residual: " << rinfo[0] << std::endl;
142                ircomm = aoclsparse_rci_interrupt;
143            }
144            break;
145
146        default:
147            break;
148        }
149    }
150    // Print the final results if the internal stopping criterion or the user defined one were met
151    switch(status)
152    {
153    case aoclsparse_status_user_stop:
154    case aoclsparse_status_success:
155        std::cout.precision(2);
156        std::cout << std::scientific;
157        aoclsparse_itsol_handle_prn_options(handle);
158        std::cout << std::endl
159                  << "Solution found: (residual = " << rinfo[0] << " in " << (int)rinfo[30]
160                  << " iterations)" << std::endl
161                  << "   Final X* = ";
162        for(int i = 0; i < n; i++)
163            std::cout << std::setw(9) << x[i] << " ";
164        std::cout << std::endl;
165        std::cout << "Expected X* = ";
166        for(int i = 0; i < n; i++)
167            std::cout << std::setw(9) << expected_sol[i] << " ";
168        std::cout << std::endl;
169        break;
170
171    case aoclsparse_status_maxit:
172        std::cout << "solve stopped after " << (int)rinfo[30] << " iterations" << std::endl
173                  << "residual = " << rinfo[0] << std::endl;
174        break;
175
176    default:
177        std::cout << "Something unexpected happened!" << std::endl;
178    }
179    aoclsparse_itsol_destroy(&handle);
180    aoclsparse_destroy_mat_descr(descr_a);
181    aoclsparse_destroy(&A);
182
183    return 0;
184}

  1/* ************************************************************************
  2 * Copyright (c) 2022-2023 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <cfloat>
 27#include <iomanip>
 28#include <iostream>
 29#include <math.h>
 30#include <vector>
 31
 32#define PREMATURE_STOP_TOLERANCE 1e-4
 33const char gmres_sol[] = "gmres_direct_s";
 34
 35float calculate_l2Norm_solvers(const float *xSol, const float *x, aoclsparse_int n)
 36{
 37    float norm = 0.0f;
 38    //residual = xSol - x
 39    //xSol obtained by initial spmv
 40    //x obtained by ILU-GMRES iterations
 41    for(aoclsparse_int i = 0; i < n; i++)
 42    {
 43        float a = xSol[i] - x[i];
 44        norm += a * a;
 45    }
 46    norm = sqrt(norm);
 47    return norm;
 48}
 49
 50aoclsparse_int monit(aoclsparse_int n,
 51                     const float   *x,
 52                     const float   *r __attribute__((unused)),
 53                     float         *rinfo,
 54                     void          *udata __attribute__((unused)))
 55{
 56    int   it  = (int)rinfo[30];
 57    float tol = PREMATURE_STOP_TOLERANCE;
 58
 59    std::ios oldState(nullptr);
 60    oldState.copyfmt(std::cout);
 61
 62    std::ios_base::fmtflags fmt = std::cout.flags();
 63    fmt |= std::ios_base::scientific | std::ios_base::right | std::ios_base::showpos;
 64
 65    if(!(it % 10))
 66    {
 67        std::cout << std::setw(5) << std::right << " iter"
 68                  << " " << std::setw(16) << std::right << "optim";
 69        for(int i = 0; i < n; i++)
 70            std::cout << std::setw(8) << std::right << "x[" << i << "]";
 71        std::cout << std::endl;
 72    }
 73    std::cout << std::setw(5) << std::right << (int)rinfo[30] << " " << std::setw(16) << std::right
 74              << std::scientific << std::setprecision(8) << rinfo[0];
 75    std::cout << std::setprecision(2) << std::showpos;
 76    for(int i = 0; i < n; i++)
 77        std::cout << " " << x[i];
 78    std::cout << std::endl;
 79    std::cout << std::resetiosflags(fmt);
 80
 81    //reset std::cout state
 82    std::cout.copyfmt(oldState);
 83
 84    if(rinfo[0] < tol) // check for premature stop
 85    {
 86        return 1; // request to interrupt
 87    }
 88    return 0;
 89}
 90
 91int main()
 92{
 93    // CSR symmetric matrix. Only the lower triangle is stored
 94    std::vector<aoclsparse_int> csr_row_ptr;
 95    std::vector<aoclsparse_int> csr_col_ind;
 96    std::vector<float>          csr_val;
 97
 98    int               m, n, nnz;
 99    aoclsparse_status exit_status = aoclsparse_status_success;
100
101    std::string filename = "cage4.mtx";
102    //symmetry = 0; //real unsymmetric, symmetry = 0%, spd = no
103    //https://www.cise.ufl.edu/research/sparse/MM/vanHeukelum/cage4.tar.gz
104    n   = 9;
105    m   = 9;
106    nnz = 49;
107    csr_row_ptr.assign({0, 5, 10, 15, 20, 26, 32, 38, 44, 49});
108    csr_col_ind.assign({0, 1, 3, 4, 7, 0, 1, 2, 4, 5, 1, 2, 3, 5, 6, 0, 2, 3, 6, 7, 0, 1, 4, 5, 6,
109                        8, 1, 2, 4, 5, 7, 8, 2, 3, 4, 6, 7, 8, 0, 3, 5, 6, 7, 8, 4, 5, 6, 7, 8});
110    csr_val.assign({0.75, 0.14, 0.11, 0.14, 0.11, 0.08, 0.69, 0.11, 0.08, 0.11, 0.09, 0.67, 0.08,
111                    0.09, 0.08, 0.09, 0.14, 0.73, 0.14, 0.09, 0.04, 0.04, 0.54, 0.14, 0.11, 0.25,
112                    0.05, 0.05, 0.08, 0.45, 0.08, 0.15, 0.04, 0.04, 0.09, 0.47, 0.09, 0.18, 0.05,
113                    0.05, 0.14, 0.11, 0.55, 0.25, 0.08, 0.08, 0.09, 0.08, 0.17});
114
115    // Create aocl sparse matrix
116    aoclsparse_matrix     A;
117    aoclsparse_index_base base = aoclsparse_index_base_zero;
118    aoclsparse_mat_descr  descr_a;
119    aoclsparse_operation  trans = aoclsparse_operation_none;
120    aoclsparse_create_scsr(&A,
121                           base,
122                           (aoclsparse_int)n,
123                           (aoclsparse_int)n,
124                           (aoclsparse_int)nnz,
125                           csr_row_ptr.data(),
126                           csr_col_ind.data(),
127                           csr_val.data());
128    aoclsparse_create_mat_descr(&descr_a);
129    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
130    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
131    aoclsparse_set_mat_index_base(descr_a, base);
132    aoclsparse_set_sv_hint(A, trans, descr_a, 100);
133    aoclsparse_optimize(A);
134
135    // Initialize initial point x0 and right hand side b
136    float *expected_sol = NULL;
137    float *x            = NULL;
138    float *b            = NULL;
139    float  norm         = 0.0;
140    float  rinfo[100];
141    float  alpha = 1.0, beta = 0.;
142    int    rs_iters = 7;
143    char   rs_iters_string[16];
144
145    expected_sol = new float[n];
146    x            = new float[n];
147    b            = new float[n];
148
149    float init_x = 1.0, ref_x = 0.5;
150    for(int i = 0; i < n; i++)
151    {
152        expected_sol[i] = ref_x;
153        x[i]            = init_x;
154    }
155
156    // generate RHS
157    // Reference SPMV CSR implementation
158    aoclsparse_smv(trans, &alpha, A, descr_a, expected_sol, &beta, b);
159
160    float                   tol    = PREMATURE_STOP_TOLERANCE;
161    aoclsparse_itsol_handle handle = nullptr;
162    // create GMRES handle
163    aoclsparse_itsol_s_init(&handle);
164
165    exit_status = aoclsparse_itsol_option_set(handle, "iterative method", "GMRES");
166    if(exit_status != aoclsparse_status_success)
167        printf("Warning an iterative method option could not be set, exit status = %d\n",
168               exit_status);
169
170    exit_status = aoclsparse_itsol_option_set(handle, "gmres preconditioner", "ILU0");
171    if(exit_status != aoclsparse_status_success)
172        printf("Warning gmres preconditioner option could not be set, exit status = %d\n",
173               exit_status);
174
175    exit_status = aoclsparse_itsol_option_set(handle, "gmres iteration limit", "50");
176    if(exit_status != aoclsparse_status_success)
177        printf("Warning gmres iteration limit option could not be set, exit status = %d\n",
178               exit_status);
179
180    sprintf(rs_iters_string, "%d", (int)rs_iters);
181    exit_status = aoclsparse_itsol_option_set(handle, "gmres restart iterations", rs_iters_string);
182    if(exit_status != aoclsparse_status_success)
183        printf("Warning gmres restart iterations option could not be set, exit status = %d\n",
184               exit_status);
185
186    aoclsparse_itsol_handle_prn_options(handle);
187
188    // Call GMRES solver
189    aoclsparse_status status;
190
191    status = aoclsparse_itsol_s_solve(handle, n, A, descr_a, b, x, rinfo, nullptr, monit, &n);
192    if(status == aoclsparse_status_success || status == aoclsparse_status_user_stop
193       || aoclsparse_status_maxit == status)
194    {
195        norm = calculate_l2Norm_solvers(expected_sol, x, n);
196
197        printf("input = %s\n", filename.c_str());
198        printf("solver = %s\n", gmres_sol);
199        printf("no of rows = %d\n", (int)m);
200        printf("no of cols = %d\n", (int)n);
201        printf("no of nnz = %d\n", (int)nnz);
202        printf("monitoring tolerance = %e\n", tol);
203        printf("restart iterations = %d\n", (int)rs_iters);
204        printf("residual achieved = %e\n", rinfo[0]);
205        printf("total iterations = %d\n", (int)rinfo[30]);
206        printf("l2 Norm = %e\n", norm);
207    }
208    else
209    {
210        std::cout << "Something unexpected happened!, Status = " << status << std::endl;
211    }
212
213    delete[] expected_sol;
214    delete[] x;
215    delete[] b;
216    aoclsparse_destroy_mat_descr(descr_a);
217    aoclsparse_destroy(&A);
218    aoclsparse_itsol_destroy(&handle);
219    printf("\n");
220    fflush(stdout);
221
222    return 0;
223}

Note

This function returns control back to the user under certain circumstances. The table in aoclsparse_itsol_rci_job indicates what actions are required to be performed by the user.

Parameters
  • handle[inout] problem handle. Needs to be previously initialized by aoclsparse_itsol_s_init or aoclsparse_itsol_d_init and then populated using either aoclsparse_itsol_s_rci_input or aoclsparse_itsol_d_rci_input, as appropriate.

  • ircomm[inout] pointer to the reverse communication instruction flag and defined in aoclsparse_itsol_rci_job.

  • u[inout] pointer to a generic vector of data. The solver will point to the data on which the operation defined by ircomm needs to be applied.

  • v[inout] pointer to a generic vector of data. The solver will ask that the result of the operation defined by ircomm be stored in v.

  • x[inout] dense vector of unknowns. On input, it should contain the initial guess from which to start the iterative process. If there is no good initial estimate guess then any arbitrary but finite values can be used. On output, it contains an estimate to the solution of the linear system of equations up to the requested tolerance, e.g. see “cg rel tolerance” or “cg abs tolerance” in Options.

  • rinfo[out] vector containing information and stats related to the iterative solve, see Information Array. This parameter can be used to monitor progress and define a custom stopping criterion when the solver returns control to user with ircomm = aoclsparse_rci_stopping_criterion.

aoclsparse_?symgs()#

aoclsparse_status aoclsparse_ssymgs(aoclsparse_operation trans, aoclsparse_matrix A, const aoclsparse_mat_descr descr, const float alpha, const float *b, float *x)#
aoclsparse_status aoclsparse_dsymgs(aoclsparse_operation trans, aoclsparse_matrix A, const aoclsparse_mat_descr descr, const double alpha, const double *b, double *x)#
aoclsparse_status aoclsparse_csymgs(aoclsparse_operation trans, aoclsparse_matrix A, const aoclsparse_mat_descr descr, const aoclsparse_float_complex alpha, const aoclsparse_float_complex *b, aoclsparse_float_complex *x)#
aoclsparse_status aoclsparse_zsymgs(aoclsparse_operation trans, aoclsparse_matrix A, const aoclsparse_mat_descr descr, const aoclsparse_double_complex alpha, const aoclsparse_double_complex *b, aoclsparse_double_complex *x)#

Symmetric Gauss Seidel(SYMGS) Preconditioner for real/complex single and double data precisions.

aoclsparse_?symgs performs an iteration of Gauss Seidel preconditioning. Krylov methods such as CG (Conjugate Gradient) and GMRES (Generalized Minimal Residual) are used to solve large sparse linear systems of the form

\[ op(A)\; x = \alpha b, \]
where \(A\) is a sparse matrix of size \(m\), \(op()\) is a linear operator, \(b\) is a dense right-hand side vector and \(x\) is the unknown dense vector, while \(\alpha\) is a scalar. This Gauss Seidel(GS) relaxation is typically used either as a preconditioner for a Krylov solver directly, or as a smoother in a V –cycle of a multigrid preconditioner to accelerate the convergence rate. The Symmetric Gauss Seidel algorithm performs a forward sweep followed by a backward sweep to maintain symmetry of the matrix operation.

To solve a linear system \(Ax = b\), Gauss Seidel(GS) iteration is based on the matrix splitting

\[ A = L + D + U = -E + D - F \]
where \(-E\) or \(L\) is strictly lower triangle, \(D\) is diagonal and \(-F\) or \(D\) is strictly upper triangle. Gauss-Seidel is best derived as element-wise (refer Yousef Saad’s book Iterative Methods for Sparse Linear Systems, Second Edition, Chapter 4.1, p. 125 onwards):
\[ x_i = \frac{1}{a_{ii}} \; \left (b_i - \sum_{j=1}^{i-1} a_{ij} \; x_j - \sum_{j=i+1}^n a_{ij} \; x_j\right) \]
where the first sum is lower triangle i.e., \(-Ex\) and the second sum is upper triangle i.e., \(-Fx\). If we iterate through the rows i=1 to n and keep overwriting/reusing the new \(x_{i}\), we get forward GS, expressed in matrix form as,
\[ (D-E) \; x_{k+1} = F \; x_k + b \]
Iterating through the rows in reverse order from i=n to 1, the upper triangle keeps using the new \(x_{k+1}\) elements and we get backward GS, expressed in matrix form as,
\[ (D-F) \; x_{k+1} = E \; x_k + b \]
The above two equations can be expressed in terms of L, D and U as follows,
\[ (L + D)\;x_1 = b - U\;x_0 \]
\[ (U + D)\;x = b - L\;x_1 \]
So, Symmetric Gauss Seidel (SYMGS) can be computed using two aoclsparse_?mv and two aoclsparse_?trsv operations.

The sparse matrix \(A\) can be either a symmetric or a Hermitian matrix, whose fill is indicated by fill_mode from the matrix descriptor descr where either upper or lower triangular portion of the matrix is used. Matrix \(A\) must be of full rank, that is, the matrix must be invertible. The linear operator \(op()\) can define the transposition or conjugate transposition operations. By default, no transposition is performed. The right-hand-side vector \(b\) and the solution vector \(x\) are dense and must be of the correct size, that is \(m\). If used as fixed point iterative method, the convergence is guaranteed for strictly diagonally dominant and symmetric positive definite matrices from any starting point, x0. However, the API can be applied to wider types of input or as a preconditioning step. Refer Yousef Saad’s Iterative Methods for Sparse Linear Systems 2nd Edition, Theorem 4.9 and related literature for mathematical theory.

1. If the matrix descriptor descr specifies that the matrix \(A\) is to be regarded as having a unitary diagonal, then the main diagonal entries of matrix \(A\) are not accessed and are considered to all be ones.

2. If the matrix \(A\) is described as upper triangular, then only the upper triangular portion of the matrix is referenced. Conversely, if the matrix \(A\) is described lower triangular, then only the lower triangular portion of the matrix is used.

3. This set of APIs allocates couple of work array buffers of size \(m\) for to store intermediate results

4. If the input matrix is of triangular type, the SGS is computed using a single aoclsparse_?trsv operation and a quick return is made without going through the 3-step reference(described above)

  1/* ************************************************************************
  2 * Copyright (c) 2024 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <cmath>
 27#include <iomanip>
 28#include <iostream>
 29#include <limits>
 30#include <vector>
 31
 32int main(void)
 33{
 34    std::cout << "------------------------------------------------" << std::endl
 35              << " Symmetric Gauss Seidel Preconditioner" << std::endl
 36              << " sample program for real data type" << std::endl
 37              << "------------------------------------------------" << std::endl
 38              << std::endl;
 39
 40    /*
 41     * This example illustrates how to use Symmetric Gauss Seidel API with an iterative solver,
 42        here we have simulated that effect using a loop. The real matrix used is
 43        A = [
 44                10   -1    2    0;
 45                -1   11   -1    3;
 46                 2   -1   10   -1;
 47                 0    3   -1    8;
 48            ]
 49     */
 50
 51    // Create a tri-diagonal matrix in CSR format
 52    const aoclsparse_int n = 4, m = 4, nnz = 14;
 53    aoclsparse_int       icrow[5] = {0, 3, 7, 11, 14};
 54    aoclsparse_int       icol[14] = {0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3};
 55    double               aval[14] = {10, -1, 2, -1, 11, -1, 3, 2, -1, 10, -1, 3, -1, 8};
 56    aoclsparse_status    status;
 57    bool                 oki, ok;
 58
 59    const double macheps      = std::numeric_limits<double>::epsilon();
 60    const double safe_macheps = (double)2.0 * macheps;
 61    double       exp_tol      = 20.0 * sqrt(safe_macheps);
 62
 63    // Create aoclsparse matrix and its descriptor
 64    aoclsparse_matrix     A;
 65    aoclsparse_index_base base = aoclsparse_index_base_zero;
 66    aoclsparse_mat_descr  descr_a;
 67    aoclsparse_operation  trans;
 68    status = aoclsparse_create_dcsr(&A, base, m, n, nnz, icrow, icol, aval);
 69    if(status != aoclsparse_status_success)
 70    {
 71        std::cerr << "Error returned from aoclsparse_create_dcsr, status = " << status << "."
 72                  << std::endl;
 73        return 3;
 74    }
 75    aoclsparse_create_mat_descr(&descr_a);
 76
 77    double alpha = 1.0;
 78    double x[m]  = {1, 1, 1, 1};
 79
 80    double              b[m] = {14, 30, 26, 35};
 81    std::vector<double> xref;
 82    xref.assign({1.0, 2.0, 3.0, 4.0});
 83
 84    // Indicate to access the lower part of matrix A
 85    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
 86    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
 87    trans = aoclsparse_operation_none;
 88
 89    status = aoclsparse_set_symgs_hint(A, trans, descr_a, 1);
 90    if(status != aoclsparse_status_success)
 91    {
 92        std::cerr << "Error returned from aoclsparse_set_symgs_hint, status = " << status << "."
 93                  << std::endl;
 94        return 3;
 95    }
 96    status = aoclsparse_optimize(A);
 97    if(status != aoclsparse_status_success)
 98    {
 99        std::cerr << "Error returned from aoclsparse_optimize, status = " << status << "."
100                  << std::endl;
101        return 3;
102    }
103    // Solve till convergence
104    std::cout << std::setw(12) << " iter";
105    for(int i = 0; i < n; i++)
106        std::cout << std::setw(15) << "x[" << i << "]";
107    std::cout << std::endl;
108    for(int i = 0; i < 8; i++)
109    {
110        status = aoclsparse_dsymgs(trans, A, descr_a, alpha, b, x);
111        if(status != aoclsparse_status_success)
112        {
113            std::cerr << "Error returned from aoclsparse_dsymgs, status = " << status << "."
114                      << std::endl;
115            return 3;
116        }
117        std::cout << std::setw(12) << (int)i << " ";
118        for(int j = 0; j < m; ++j)
119        {
120            std::cout << std::setw(16) << std::scientific << x[j] << " ";
121        }
122        std::cout << std::endl;
123    }
124    // Print and check the result
125    std::cout << "Solving A x = alpha b" << std::endl;
126    std::cout << "  where x and b are dense vectors" << std::endl;
127    std::cout << "  Solution found after 8 iterations, x = " << std::endl;
128    std::cout << std::fixed;
129    std::cout.precision(6);
130    ok = true;
131    for(int i = 0; i < m; ++i)
132    {
133        oki = std::abs(x[i] - xref[i]) <= exp_tol;
134        std::cout << x[i] << (oki ? "  " : "! ");
135        ok &= oki;
136    }
137    std::cout << std::endl;
138
139    // Destroy the aoclsparse memory
140    aoclsparse_destroy_mat_descr(descr_a);
141    aoclsparse_destroy(&A);
142
143    return ok ? 0 : 5;
144}

  1/* ************************************************************************
  2 * Copyright (c) 2024 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <cmath>
 27#include <complex>
 28#include <iomanip>
 29#include <iostream>
 30#include <limits>
 31#include <vector>
 32
 33int main(void)
 34{
 35    std::cout << "------------------------------------------------" << std::endl
 36              << " Symmetric Gauss Seidel Preconditioner" << std::endl
 37              << " sample program for complex data type" << std::endl
 38              << "------------------------------------------------" << std::endl
 39              << std::endl;
 40
 41    /*
 42     * This example illustrates how to use Symmetric Gauss Seidel API for complex data
 43        with an iterative solver, here we have simulated that effect using a loop.
 44        The complex matrix used is
 45        A = [
 46                   10+i  -1-0.1i    2+0.2i        0;
 47                -1-0.1i  11+1.1i   -1-0.1i   3+0.3i;
 48                 2+0.2i  -1-0.1i      10+i  -1-0.1i;
 49                      0   3+0.3i   -1-0.1i   8+0.8i;
 50            ]
 51     */
 52
 53    // Create a tri-diagonal matrix in CSR format
 54    const aoclsparse_int                   n = 4, m = 4, nnz = 14;
 55    aoclsparse_int                         icrow[5] = {0, 3, 7, 11, 14};
 56    aoclsparse_int                         icol[14] = {0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3};
 57    std::vector<aoclsparse_double_complex> aval;
 58    // clang-format off
 59    aval.assign({{10,1}, {-1,-0.1}, {2,0.2}, {-1,-0.1},
 60                 {11,1.1}, {-1,-0.1}, {3,0.3}, {2,0.2},
 61                 {-1,-0.1}, {10,1}, {-1,-0.1}, {3, 0.3},
 62                 {-1,-0.1}, {8, 0.8}});
 63    // clang-format on
 64    aoclsparse_status status;
 65    bool              oki, ok;
 66
 67    const double macheps      = std::numeric_limits<double>::epsilon();
 68    const double safe_macheps = (double)2.0 * macheps;
 69    double       exp_tol      = 20.0 * sqrt(safe_macheps);
 70
 71    // Create aoclsparse matrix and its descriptor
 72    aoclsparse_matrix     A;
 73    aoclsparse_index_base base = aoclsparse_index_base_zero;
 74    aoclsparse_mat_descr  descr_a;
 75    aoclsparse_operation  trans;
 76    status = aoclsparse_create_zcsr(&A, base, m, n, nnz, icrow, icol, &aval[0]);
 77    if(status != aoclsparse_status_success)
 78    {
 79        std::cerr << "Error returned from aoclsparse_create_dcsr, status = " << status << "."
 80                  << std::endl;
 81        return 3;
 82    }
 83    aoclsparse_create_mat_descr(&descr_a);
 84
 85    aoclsparse_double_complex alpha = {1.0, 0.};
 86
 87    std::vector<aoclsparse_double_complex> x, b, xref;
 88    x.assign({{1, 0.1}, {1, 0.1}, {1, 0.1}, {1, 0.1}});
 89    b.assign({{13.859999999999999, 2.7999999999999998},
 90              {29.699999999999999, 6},
 91              {25.739999999999998, 5.2000000000000002},
 92              {34.649999999999999, 7}});
 93    xref.assign({{0.99999999992700483, 0.099999999992700442},
 94                 {2.0000000217847944, 0.20000000217847949},
 95                 {3.0000000112573724, 0.30000000112573733},
 96                 {3.9999999237056727, 0.39999999237056733}});
 97
 98    // Indicate to access the lower part of matrix A
 99    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_symmetric);
100    aoclsparse_set_mat_fill_mode(descr_a, aoclsparse_fill_mode_lower);
101    trans = aoclsparse_operation_none;
102
103    status = aoclsparse_set_symgs_hint(A, trans, descr_a, 1);
104    if(status != aoclsparse_status_success)
105    {
106        std::cerr << "Error returned from aoclsparse_set_symgs_hint, status = " << status << "."
107                  << std::endl;
108        return 3;
109    }
110    status = aoclsparse_optimize(A);
111    if(status != aoclsparse_status_success)
112    {
113        std::cerr << "Error returned from aoclsparse_optimize, status = " << status << "."
114                  << std::endl;
115        return 3;
116    }
117    // Solve till convergence
118    std::cout << std::setw(12) << " iter";
119    for(int i = 0; i < n; i++)
120        std::cout << std::setw(33) << "x[" << i << "]";
121    std::cout << std::endl;
122    for(int i = 0; i < 8; i++)
123    {
124        status = aoclsparse_zsymgs(trans, A, descr_a, alpha, &b[0], &x[0]);
125        if(status != aoclsparse_status_success)
126        {
127            std::cerr << "Error returned from aoclsparse_zsymgs, status = " << status << "."
128                      << std::endl;
129            return 3;
130        }
131        std::cout << std::setw(12) << (int)i << " ";
132        for(int j = 0; j < m; ++j)
133        {
134            std::cout << std::setw(8) << std::scientific << std::setprecision(6) << "(" << x[j].real
135                      << ", " << x[j].imag << ")";
136        }
137        std::cout << std::endl;
138    }
139    // Print and check the result
140    std::cout << "Solving A x = alpha b" << std::endl;
141    std::cout << "  where x and b are dense vectors" << std::endl;
142    std::cout << "  Solution found after 8 iterations, x = " << std::endl;
143    std::cout << std::fixed;
144    std::cout.precision(6);
145    ok = true;
146    for(int i = 0; i < m; ++i)
147    {
148        oki = std::abs(x[i].real - xref[i].real) <= exp_tol
149              && std::abs(x[i].imag - xref[i].imag) <= exp_tol;
150        std::cout << "(" << x[i].real << ", " << x[i].imag << "i) " << (oki ? "  " : "! ");
151        ok &= oki;
152    }
153    std::cout << std::endl;
154
155    // Destroy the aoclsparse memory
156    aoclsparse_destroy_mat_descr(descr_a);
157    aoclsparse_destroy(&A);
158
159    return ok ? 0 : 5;
160}

Note

Parameters
Return values
  • aoclsparse_status_success – indicates that the operation completed successfully.

  • aoclsparse_status_invalid_size – informs that either m, n or nnz is invalid. The error code also informs if the given sparse matrix \(A\) is not square.

  • aoclsparse_status_invalid_value – informs that either base, trans, matrix type descr->type or fill mode descr->fill_mode is invalid. If the sparse matrix \(A\) is not of full rank, the error code is returned to indicate that the linear system cannot be solved.

  • aoclsparse_status_invalid_pointer – informs that either descr, A, b, or x pointer is invalid.

  • aoclsparse_status_not_implemented – this error occurs when the provided matrix’s aoclsparse_fill_mode is aoclsparse_diag_type_unit or the input format is not aoclsparse_csr_mat, or when aoclsparse_matrix_type is aoclsparse_matrix_type_general and trans is aoclsparse_operation_conjugate_transpose.

Warning

doxygenfunction: Cannot find function “aoclsparse_ssymgs_mv” in doxygen xml output for project “aocl-sparse” from directory: /home/janfiala/dev/aocl-sparse/sparse_builds/gcc_dbg/docs/xml

Warning

doxygenfunction: Cannot find function “aoclsparse_dsymgs_mv” in doxygen xml output for project “aocl-sparse” from directory: /home/janfiala/dev/aocl-sparse/sparse_builds/gcc_dbg/docs/xml

Warning

doxygenfunction: Cannot find function “aoclsparse_csymgs_mv” in doxygen xml output for project “aocl-sparse” from directory: /home/janfiala/dev/aocl-sparse/sparse_builds/gcc_dbg/docs/xml

Warning

doxygenfunction: Cannot find function “aoclsparse_zsymgs_mv” in doxygen xml output for project “aocl-sparse” from directory: /home/janfiala/dev/aocl-sparse/sparse_builds/gcc_dbg/docs/xml

aoclsparse_?sorv()#

aoclsparse_status aoclsparse_ssorv(aoclsparse_sor_type sor_type, const aoclsparse_mat_descr descr, const aoclsparse_matrix A, float omega, float alpha, float *x, const float *b)#
aoclsparse_status aoclsparse_dsorv(aoclsparse_sor_type sor_type, const aoclsparse_mat_descr descr, const aoclsparse_matrix A, double omega, double alpha, double *x, const double *b)#

Performs successive over-relaxation preconditioner operation for single and double precision datatypes to solve a linear system of equations \(Ax=b\).

aoclsparse_?sorv performs successive over-relaxation preconditioner on a linear system of equations represented using a sparse matrix \(A\) in CSR storage format. This is an iterative technique that solves the left hand side of this expression for x, using an initial guess for x

\[(D + \omega \, L) \, x^1 = \omega \, b - (\omega \, U + (\omega -1) \, D) \, x^0\]
where \(A = L + D + U\), \(x^0\) is an input vector x and \(x^1\) is an output stored in vector x.

Initially

\[\begin{split} x^0 = \left\{ \begin{array}{ll} alpha * x^0, & \text{ if } alpha \neq 0 \\ 0, & \text{ if } alpha = 0 \end{array} \right. \end{split}\]
The convergence is guaranteed for strictly diagonally dominant and positive definite matrices from any starting point, \(x^0\). API returns the vector x after single iteration. Caller can invoke this function in a loop until their desired convergence is reached.

NOTE:

1. Input CSR matrix should have non-zero full diagonals with each diagonal occurring only once in a row.

2. API supports forward sweep on general matrix for single and double precision datatypes.

  1/* ************************************************************************
  2 * Copyright (c) 2024 Advanced Micro Devices, Inc.
  3 *
  4 * Permission is hereby granted, free of charge, to any person obtaining a copy
  5 * of this software and associated documentation files (the "Software"), to deal
  6 * in the Software without restriction, including without limitation the rights
  7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8 * copies of the Software, and to permit persons to whom the Software is
  9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 *
 22 * ************************************************************************ */
 23
 24#include "aoclsparse.h"
 25
 26#include <cmath>
 27#include <iomanip>
 28#include <iostream>
 29#include <limits>
 30#include <vector>
 31
 32int main(void)
 33{
 34    std::cout << "------------------------------------------------" << std::endl
 35              << " Successive over-relaxation Preconditioner" << std::endl
 36              << " sample program for real data type" << std::endl
 37              << "------------------------------------------------" << std::endl
 38              << std::endl;
 39
 40    /*
 41     * This example illustrates how to use Successive over-relaxation API to solve
 42     * linear system of equations. The real matrix used is
 43     *     |  111.1   2.345    0.0      0.0   |
 44     * A = |   3.12   9.87    -56.2     0.0   |
 45     *     |   0.0     0.0   -39.678    0.0   |
 46     *     | 32.0987  76.9   -903.40  -25.106 |
 47     */
 48
 49    // Create a tri-diagonal matrix in CSR format
 50    const aoclsparse_int n = 4, m = 4, nnz = 10;
 51    aoclsparse_int       icrow[5] = {0, 2, 5, 6, 10};
 52    aoclsparse_int       icol[10] = {0, 1, 0, 1, 2, 2, 1, 3, 2, 0};
 53    double aval[10] = {111.1, 2.345, 3.12, 9.87, -56.2, -39.678, 76.9, -25.106, -903.40, 32.0987};
 54    aoclsparse_status   status;
 55    bool                oki, ok;
 56    double              omega = 0.5;
 57    double              alpha = 1.0;
 58    double              x[m]  = {1, -41, 5.7, 0.341};
 59    double              b[m]  = {157.5045, -489.033, -321.3918, -7433.72955};
 60    std::vector<double> xref
 61        = {1.6415369036903691, -29.305197322163828, 6.9000000000000004, -19.757185084519875};
 62    const double macheps      = std::numeric_limits<double>::epsilon();
 63    const double safe_macheps = (double)2.0 * macheps;
 64    double       exp_tol      = 20.0 * sqrt(safe_macheps);
 65
 66    // Create aoclsparse matrix and its descriptor
 67    aoclsparse_matrix     A;
 68    aoclsparse_index_base base = aoclsparse_index_base_zero;
 69    aoclsparse_mat_descr  descr_a;
 70    status = aoclsparse_create_dcsr(&A, base, m, n, nnz, icrow, icol, aval);
 71    if(status != aoclsparse_status_success)
 72    {
 73        std::cerr << "Error returned from aoclsparse_create_dcsr, status = " << status << "."
 74                  << std::endl;
 75        return 3;
 76    }
 77    aoclsparse_create_mat_descr(&descr_a);
 78    aoclsparse_set_mat_type(descr_a, aoclsparse_matrix_type_general);
 79
 80    status = aoclsparse_set_sorv_hint(A, descr_a, aoclsparse_sor_forward, 1);
 81    if(status != aoclsparse_status_success)
 82    {
 83        std::cerr << "Error returned from aoclsparse_set_sorv_hint, status = " << status << "."
 84                  << std::endl;
 85        return 3;
 86    }
 87    status = aoclsparse_optimize(A);
 88    if(status != aoclsparse_status_success)
 89    {
 90        std::cerr << "Error returned from aoclsparse_optimize, status = " << status << "."
 91                  << std::endl;
 92        return 3;
 93    }
 94    // Solve
 95    status = aoclsparse_dsorv(aoclsparse_sor_forward, descr_a, A, omega, alpha, x, b);
 96    if(status != aoclsparse_status_success)
 97    {
 98        std::cerr << "Error returned from aoclsparse_dsorv, status = " << status << "."
 99                  << std::endl;
100        return 3;
101    }
102    // Print and check the result
103    std::cout << "Solving A x = b where x and b are dense vectors" << std::endl;
104    std::cout << "Solution vector x = " << std::endl;
105    std::cout << std::fixed;
106    std::cout.precision(12);
107    ok = true;
108    for(int i = 0; i < m; ++i)
109    {
110        oki = std::abs(x[i] - xref[i]) <= exp_tol;
111        std::cout << x[i] << (oki ? "  " : "! ");
112        ok &= oki;
113    }
114    std::cout << std::endl;
115
116    // Destroy the aoclsparse memory
117    aoclsparse_destroy_mat_descr(descr_a);
118    aoclsparse_destroy(&A);
119
120    return ok ? 0 : 5;
121}
Parameters
  • sor_type[in] Selects the type of operation performed by the preconditioner. Only aoclsparse_sor_forward is supported at present.

  • descr[in] Descriptor of A. Only aoclsparse_matrix_type_general is supported at present. As a consequence, all other parameters within the descriptor are ignored.

  • A[in] Matrix structure containing a square sparse matrix \(A\) of size \(m \times m\).

  • omega[in] Relaxation factor. For better convergence, 0 < \(\omega\) < 2. If \(\omega\) = 1, the preconditioner is equivalent to the Gauss-Seidel method.

  • alpha[in] Scalar value used to normalize or set to zero the vector x that holds an initial guess.

  • x[inout] A vector of \(m\) elements that holds an initial guess as well as the solution vector.

  • b[in] A vector of \(m\) elements that holds the right-hand side of the equation being solved.

Return values
  • aoclsparse_status_success – Completed successfully.

  • aoclsparse_status_invalid_pointer – One or more of the pointers A, descr, x or b are invalid.

  • aoclsparse_status_wrong_type – Data type of A does not match the function.

  • aoclsparse_status_not_implemented – Expecting general matrix in CSR format for single or double precision datatypes with aoclsparse_sor_forward.

  • aoclsparse_status_invalid_size – Matrix is not square.

  • aoclsparse_status_invalid_valueM or N is set to a negative value; or A, descr or sor_type has invalid value; or presence of zero-valued or repeated diagonal elements.