-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathExampleHelper.hpp
More file actions
403 lines (362 loc) · 14.4 KB
/
ExampleHelper.hpp
File metadata and controls
403 lines (362 loc) · 14.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
#pragma once
#include <cassert>
#include <cmath>
#include <iostream>
#include <resolve/LinSolverIterative.hpp>
#include <resolve/matrix/MatrixHandler.hpp>
#include <resolve/matrix/Sparse.hpp>
#include <resolve/vector/Vector.hpp>
#include <resolve/vector/VectorHandler.hpp>
namespace ReSolve
{
namespace examples
{
/**
* @brief Prints linear system info.
*
* @param name - pathname of the system matrix
* @param A - pointer to the system matrix
*/
void printSystemInfo(const std::string& matrix_pathname, matrix::Sparse* A)
{
std::cout << std::endl;
std::cout << "========================================================================================================================\n";
std::cout << "Reading: " << matrix_pathname << std::endl;
std::cout << "========================================================================================================================\n";
std::cout << std::endl;
std::cout << "Finished reading the matrix and rhs, size: " << A->getNumRows() << " x " << A->getNumColumns()
<< ", nnz: " << A->getNnz()
<< ", symmetric? " << A->symmetric()
<< ", Expanded? " << A->expanded() << std::endl;
}
/**
* @brief Test helper class template
*
* This is header-only implementation of several utility functions used by
* multiple functionality tests, such as error norm calculations. To use,
* simply include this header in the test.
*
* @tparam workspace_type
*/
template <class workspace_type>
class ExampleHelper
{
public:
/**
* @brief Default constructor
*
* Initializes matrix and vector handlers.
*
* @param[in,out] workspace - workspace for matrix and vector handlers
*
* @pre Workspace handles are initialized
*
* @post Handlers are instantiated.
* allocated
*/
ExampleHelper(workspace_type& workspace)
: mh_(&workspace),
vh_(&workspace)
{
memspace_ = ReSolve::memory::DEVICE;
if (mh_.getIsCudaEnabled())
{
hardware_backend_ = "CUDA";
}
else if (mh_.getIsHipEnabled())
{
hardware_backend_ = "HIP";
}
else
{
hardware_backend_ = "CPU";
memspace_ = ReSolve::memory::HOST;
}
}
/**
* @brief Destroy the ExampleHelper object
*
* @post Vectors res_ and x_true_ are deleted.
*
*/
~ExampleHelper()
{
if (res_)
{
delete res_;
res_ = nullptr;
}
if (x_true_)
{
delete x_true_;
x_true_ = nullptr;
}
}
std::string getHardwareBackend() const
{
return hardware_backend_;
}
/**
* @brief Set the new linear system together with its computed solution
* and compute solution error and residual norms.
*
* This will set the new system A*x = r and compute related error norms.
*
* @param A[in] - Linear system matrix
* @param r[in] - Linear system right-hand side
* @param x[in] - Computed solution of the linear system
*/
void setSystem(ReSolve::matrix::Sparse* A,
ReSolve::vector::Vector* r,
ReSolve::vector::Vector* x)
{
assert((res_ == nullptr) && (x_true_ == nullptr));
A_ = A;
r_ = r;
x_ = x;
res_ = new ReSolve::vector::Vector(A->getNumRows());
computeNorms();
}
/**
* @brief Set the new linear system together with its computed solution
* and compute solution error and residual norms.
*
* This is to be used after values in A and r are updated.
*
* @todo This method probably does not need any input parameters.
*
* @param A[in] - Linear system matrix
* @param r[in] - Linear system right-hand side
* @param x[in] - Computed solution of the linear system
*/
void resetSystem(ReSolve::matrix::Sparse* A,
ReSolve::vector::Vector* r,
ReSolve::vector::Vector* x)
{
A_ = A;
r_ = r;
x_ = x;
if (res_ == nullptr)
{
res_ = new ReSolve::vector::Vector(A->getNumRows());
}
computeNorms();
}
/// Return L2 norm of the linear system residual.
ReSolve::real_type getNormResidual()
{
return norm_res_;
}
/// Return relative residual norm.
ReSolve::real_type getNormRelativeResidual()
{
return norm_res_ / norm_rhs_;
}
/// Minimalistic summary
void printShortSummary()
{
std::cout << "\t2-Norm of the residual: "
<< std::scientific << std::setprecision(16)
<< getNormRelativeResidual() << "\n";
}
/// Summary of direct solve
void printSummary()
{
std::cout << "\t 2-Norm of the residual (before IR): "
<< std::scientific << std::setprecision(16)
<< getNormRelativeResidual() << "\n";
std::cout << std::scientific << std::setprecision(16)
<< "\t Matrix inf norm: " << inf_norm_A_ << "\n"
<< "\t Residual inf norm: " << inf_norm_res_ << "\n"
<< "\t Solution inf norm: " << inf_norm_x_ << "\n"
<< "\t Norm of scaled residuals: " << nsr_norm_ << "\n";
}
/// Summary of error norms for an iterative refinement test.
void printIrSummary(ReSolve::LinSolverIterative* ls)
{
std::cout << "FGMRES: init nrm: "
<< std::scientific << std::setprecision(16)
<< ls->getInitResidualNorm() / norm_rhs_
<< " final nrm: "
<< ls->getFinalResidualNorm() / norm_rhs_
<< " iter: " << ls->getNumIter() << "\n";
}
/// Summary of error norms for an iterative solver test.
void printIterativeSolverSummary(ReSolve::LinSolverIterative* ls)
{
std::cout << std::setprecision(16) << std::scientific;
std::cout << "\t Initial residual norm ||b-A*x|| : " << ls->getInitResidualNorm() << "\n";
std::cout << "\t Initial relative residual norm ||b-A*x||/||b|| : " << ls->getInitResidualNorm() / norm_rhs_ << "\n";
std::cout << "\t Final residual norm ||b-A*x|| : " << ls->getFinalResidualNorm() << "\n";
std::cout << "\t Final relative residual norm ||b-A*x||/||b|| : " << ls->getFinalResidualNorm() / norm_rhs_ << "\n";
std::cout << "\t Number of iterations : " << ls->getNumIter() << "\n";
}
/// Check the relative residual norm against `tolerance`.
int checkResult(ReSolve::real_type tolerance)
{
int error_sum = 0;
ReSolve::real_type norm = norm_res_ / norm_rhs_;
if (!std::isfinite(norm))
{
std::cout << "Result is not a finite number!\n";
error_sum++;
}
if (norm > tolerance)
{
std::cout << "Result inaccurate!\n";
error_sum++;
}
return error_sum;
}
/**
* @brief Verify the computation of the norm of scaled residuals.
*
* The norm value is provided as the input. This function computes
* the norm of scaled residuals for the system that has been set
* by the constructor or (re)setSystem functions.
*
* @param nsr_system - norm of scaled residuals value to be verified
* @return int - 0 if the result is correct, error code otherwise
*/
int checkNormOfScaledResiduals(ReSolve::real_type nsr_system)
{
using namespace ReSolve;
int error_sum = 0;
// Compute residual norm to get updated vector res_
res_->copyDataFrom(r_, memspace_, memspace_);
norm_res_ = computeResidualNorm(*A_, *x_, *res_, memspace_);
// Compute norm of scaled residuals
real_type inf_norm_A = 0.0;
mh_.matrixInfNorm(A_, &inf_norm_A, memspace_);
real_type inf_norm_x = vh_.infNorm(x_, memspace_);
real_type inf_norm_res = vh_.infNorm(res_, memspace_);
real_type nsr_norm = inf_norm_res / (inf_norm_A * inf_norm_x);
real_type error = std::abs(nsr_system - nsr_norm) / nsr_norm;
// Test norm of scaled residuals method in SystemSolver
if (error > 10.0 * std::numeric_limits<real_type>::epsilon())
{
std::cout << "Norm of scaled residuals computation failed:\n";
std::cout << std::scientific << std::setprecision(16)
<< "\tMatrix inf norm : " << inf_norm_A << "\n"
<< "\tResidual inf norm : " << inf_norm_res << "\n"
<< "\tSolution inf norm : " << inf_norm_x << "\n"
<< "\tNorm of scaled residuals : " << nsr_norm << "\n"
<< "\tNorm of scaled residuals (system): " << nsr_system << "\n\n";
}
return error_sum;
}
/**
* @brief Verify the computation of the relative residual norm.
*
* The norm value is provided as the input. This function computes
* the relative residual norm for the system that has been set
* by the constructor or (re)setSystem functions.
*
* @param rrn_system - relative residual norm value to be verified
* @return int - 0 if the result is correct, error code otherwise
*/
int checkRelativeResidualNorm(ReSolve::real_type rrn_system)
{
using namespace ReSolve;
int error_sum = 0;
// Compute residual norm
res_->copyDataFrom(r_, memspace_, memspace_);
norm_res_ = computeResidualNorm(*A_, *x_, *res_, memspace_);
real_type error = std::abs(norm_rhs_ * rrn_system - norm_res_) / norm_res_;
if (error > 10.0 * std::numeric_limits<real_type>::epsilon())
{
std::cout << "Relative residual norm computation failed:\n";
std::cout << std::scientific << std::setprecision(16)
<< "\tTest value : " << norm_res_ / norm_rhs_ << "\n"
<< "\tSystemSolver computed : " << rrn_system << "\n\n";
error_sum++;
}
return error_sum;
}
/**
* @brief Verify the computation of the residual norm.
*
* The norm value is provided as the input. This function computes
* the residual norm for the system that has been set by the constructor
* or (re)setSystem functions.
*
* @param rrn_system - residual norm value to be verified
* @return int - 0 if the result is correct, error code otherwise
*/
int checkResidualNorm(ReSolve::real_type rn_system)
{
using namespace ReSolve;
int error_sum = 0;
// Compute residual norm
res_->copyDataFrom(r_, memspace_, memspace_);
norm_res_ = computeResidualNorm(*A_, *x_, *res_, memspace_);
real_type error = std::abs(rn_system - norm_res_) / norm_res_;
if (error > 10.0 * std::numeric_limits<real_type>::epsilon())
{
std::cout << "Residual norm computation failed:\n";
std::cout << std::scientific << std::setprecision(16)
<< "\tTest value : " << norm_res_ << "\n"
<< "\tSystemSolver computed : " << rn_system << "\n\n";
error_sum++;
}
return error_sum;
}
private:
/// Compute error norms.
void computeNorms()
{
// Compute rhs and residual norms
res_->copyDataFrom(r_, memspace_, memspace_);
norm_rhs_ = norm2(*r_, memspace_);
norm_res_ = computeResidualNorm(*A_, *x_, *res_, memspace_);
// Compute norm of scaled residuals
mh_.matrixInfNorm(A_, &inf_norm_A_, memspace_);
inf_norm_x_ = vh_.infNorm(x_, memspace_);
inf_norm_res_ = vh_.infNorm(res_, memspace_);
nsr_norm_ = inf_norm_res_ / (inf_norm_A_ * inf_norm_x_);
}
/**
* @brief Computes residual norm = || A * x - r ||_2
*
* @param[in] A - system matrix
* @param[in] x - computed solution of the system
* @param[in,out] r - system right-hand side, residual vector
* @param[in] memspace memory space where to computate the norm
* @return ReSolve::real_type
*
* @post r is overwritten with residual values
*/
ReSolve::real_type computeResidualNorm(ReSolve::matrix::Sparse& A,
ReSolve::vector::Vector& x,
ReSolve::vector::Vector& r,
ReSolve::memory::MemorySpace memspace)
{
using namespace ReSolve::constants;
mh_.matvec(&A, &x, &r, &ONE, &MINUS_ONE, memspace); // r := A * x - r
return norm2(r, memspace);
}
/// Compute L2 norm of vector `r` in memory space `memspace`.
ReSolve::real_type norm2(ReSolve::vector::Vector& r,
ReSolve::memory::MemorySpace memspace)
{
return std::sqrt(vh_.dot(&r, &r, memspace));
}
private:
ReSolve::matrix::Sparse* A_; ///< pointer to system matrix
ReSolve::vector::Vector* r_; ///< pointer to system right-hand side
ReSolve::vector::Vector* x_; ///< pointer to the computed solution
ReSolve::MatrixHandler mh_; ///< matrix handler instance
ReSolve::VectorHandler vh_; ///< vector handler instance
ReSolve::vector::Vector* res_{nullptr}; ///< pointer to residual vector
ReSolve::vector::Vector* x_true_{nullptr}; ///< pointer to solution error vector
ReSolve::real_type norm_rhs_{0.0}; ///< right-hand side vector norm
ReSolve::real_type norm_res_{0.0}; ///< residual vector norm
real_type inf_norm_A_{0.0}; ///< infinity norm of matrix A
real_type inf_norm_x_{0.0}; ///< infinity norm of solution x
real_type inf_norm_res_{0.0}; ///< infinity norm of res = A*x - r
real_type nsr_norm_{0.0}; ///< norm of scaled residuals
ReSolve::memory::MemorySpace memspace_{ReSolve::memory::HOST};
std::string hardware_backend_{"NONE"};
};
} // namespace examples
} // namespace ReSolve