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
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.
Recommended Workflow#
For solving a linear system of equations, the following workflow is recommended:
Call
aoclsparse_itsol_s_init()oraoclsparse_itsol_d_init()to initialize aoclsparse_itsol_handle.Choose the solver and adjust its behaviour by setting optional parameters with
aoclsparse_itsol_option_set(), see there all options available.If the reverse communication interface is desired, define the system’s input with
aoclsparse_itsol_s_rci_input()(oraoclsparse_itsol_d_rci_input()).Solve the system with either using direct interface
aoclsparse_itsol_s_solve()(oraoclsparse_itsol_d_solve()) or reverse communication interfaceaoclsparse_itsol_s_rci_solve()(oraoclsparse_itsol_d_rci_solve())Free the memory with
aoclsparse_itsol_destroy().
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#
Collaborative. Acceleration methods. Encyclopedia of Mathematics, 2023 (retrieved in). https://encyclopediaofmath.org/index.php?title=Acceleration_methods&oldid=52131.
Collaborative. Conjugate gradients, method of. Encyclopedia of Mathematics, 2023 (retrieved in). https://encyclopediaofmath.org/index.php?title=Conjugate_gradients,_method_of&oldid=46470.
Yousef Saad. Iterative Methods for Sparse Linear Systems. 2nd edition, 2003.
API documentation#
aoclsparse_itsol_rci_job#
-
enum aoclsparse_itsol_rci_job#
Values of
ircommused 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
xcontains the solution.
-
enumerator aoclsparse_rci_start#
initial value of the
ircommflag, 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.
-
enumerator aoclsparse_rci_interrupt#
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. Thishandleis used by iterative solvers (itsol) suite to setup options, define which solver to use, etc.Note
Once the
handleis 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
handlepreviously 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
handlethat 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 bymat. The right hand-side is the dense vectorband the vector of unknowns isx. 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:
Call aoclsparse_itsol_s_init or aoclsparse_itsol_d_init to initialize the problem
handle( aoclsparse_itsol_handle).Choose the solver and adjust its behaviour by setting optional parameters with aoclsparse_itsol_option_set, see also Options.
Solve the system by calling aoclsparse_itsol_s_solve or aoclsparse_itsol_d_solve.
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.
If solver terminated successfully then vector
xcontains the solution.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 descriptordescrneed 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
nthe problem size,xthe current iterate,rthe current residual vector ( \(r = Ax-b\)),rinfothe current solver’s stats, see Information Array, andudataa 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 vectorb.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, andbare invalid.aoclsparse_status_wrong_type –
handlewas initialized with a different floating point precision than requested here, e.g. aoclsparse_itsol_d_init (double precision) was used to initializehandlebut 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_value –
nwas 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 vectorband the vector of unknowns isx. 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
ircommindicating 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:
Call aoclsparse_itsol_s_init or aoclsparse_itsol_d_init to initialize the problem
handle( aoclsparse_itsol_handle)Choose the solver and adjust its behaviour by setting optional parameters with aoclsparse_itsol_option_set, see also Options.
Define the problem size and right-hand side vector \(b\) with aoclsparse_itsol_d_rci_input.
Solve the system with either aoclsparse_itsol_s_rci_solve or aoclsparse_itsol_d_rci_solve.
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.
If solver terminated successfully then vector
xcontains the solution.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
ircommneeds to be applied.v – [inout] pointer to a generic vector of data. The solver will ask that the result of the operation defined by
ircommbe stored inv.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_?symgsperforms 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 rowsi=1tonand 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 fromi=nto1, 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 ofL,DandUas 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 twoaoclsparse_?mvand twoaoclsparse_?trsvoperations.The sparse matrix \(A\) can be either a symmetric or a Hermitian matrix, whose fill is indicated by
fill_modefrom the matrix descriptordescrwhere 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
descrspecifies 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_?trsvoperation 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
trans – [in] matrix operation to perform on \(A\). Possible values are aoclsparse_operation_none, aoclsparse_operation_transpose, and aoclsparse_operation_conjugate_transpose.
A – [in] sparse matrix \(A\) of size \(m\).
descr – [in] descriptor of the sparse matrix \(A\).
alpha – [in] scalar \(\alpha\).
b – [in] dense vector, of size \(m\).
x – [out] solution vector \(x,\) dense vector of size \(m\).
- Return values
aoclsparse_status_success – indicates that the operation completed successfully.
aoclsparse_status_invalid_size – informs that either
m,nornnzis 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 typedescr->typeor fill modedescr->fill_modeis 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, orxpointer 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
transis 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_?sorvperforms 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 forx, using an initial guess forx\[(D + \omega \, L) \, x^1 = \omega \, b - (\omega \, U + (\omega -1) \, D) \, x^0\]where \(A = L + D + U\), \(x^0\) is an input vectorxand \(x^1\) is an output stored in vectorx.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
xthat 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,xorbare invalid.aoclsparse_status_wrong_type – Data type of
Adoes 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_value –
MorNis set to a negative value; orA,descrorsor_typehas invalid value; or presence of zero-valued or repeated diagonal elements.