Skip to content

Commit bd574b0

Browse files
Added new API call AMGX_matrix_check_symmetry (#272)
This can be run on a single process to test whether the provided matrix is symmetric (structurally or completely). Also added test to the amgx_mpi_capi example, behind the flag -cs.
1 parent a2692c2 commit bd574b0

File tree

6 files changed

+152
-13
lines changed

6 files changed

+152
-13
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ endif()
173173
string(TOUPPER ${CMAKE_BUILD_TYPE} UPP_BUILD_NAME)
174174
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} ${CUDA_NVCC_FLAGS_${UPP_BUILD_NAME}})
175175

176+
# Enable device lambdas
177+
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} --extended-lambda)
178+
176179
# Add errors for execution space warnings and enable NVTX ranges
177180
set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} --Werror cross-execution-space-call ${NVTXRANGE_FLAG})
178181

examples/amgx_mpi_capi.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,25 @@ int main(int argc, char **argv)
327327
errAndExit("ERROR: no linear system was specified");
328328
}
329329

330+
pidx = findParamIndex(argv, argc, "-cs");
331+
if(pidx != -1)
332+
{
333+
int structurally_symmetric = 0;
334+
int symmetric = 0;
335+
336+
printf("Checking matrix symmetry\n");
337+
AMGX_matrix_check_symmetry(A, &structurally_symmetric, &symmetric);
338+
if(symmetric) {
339+
printf("A is symmetric\n");
340+
}
341+
else if(structurally_symmetric) {
342+
printf("A is structurally_symmetric\n");
343+
}
344+
else {
345+
printf("A is assymetric\n");
346+
}
347+
}
348+
330349
//free temporary storage
331350
if (partition_vector != NULL) { free(partition_vector); }
332351

examples/amgx_mpi_poisson7.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,6 @@ int main(int argc, char **argv)
129129
//versions
130130
int major, minor;
131131
char *ver, *date, *time;
132-
//input matrix and rhs/solution
133-
int *partition_sizes = NULL;
134-
int *partition_vector = NULL;
135-
int partition_vector_size = 0;
136132
//library handles
137133
AMGX_Mode mode;
138134
AMGX_config_handle cfg;

include/amgx_c.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,11 @@ AMGX_RC AMGX_API AMGX_matrix_upload_all_global_32
608608
const void *diag_data,
609609
AMGX_distribution_handle distribution);
610610

611+
AMGX_RC AMGX_API AMGX_check_matrix_symmetry
612+
(AMGX_matrix_handle mtx,
613+
int* structurally_symmetric,
614+
int* symmetric);
615+
611616
/*********************************************************
612617
* C-API deprecated
613618
*********************************************************/

src/amgx_c.cu

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
#include <vector.h>
5656
#include <thrust_wrapper.h>
5757

58+
#include "matrix_analysis.h"
5859
#include "amgx_types/util.h"
5960
#include "amgx_types/rand.h"
6061
#include "amgx_c_wrappers.inl"
@@ -2356,11 +2357,8 @@ extern "C" {
23562357
{
23572358
std::string deprecated("The AMGX_initialize_plugins API call is deprecated and can be safely removed.\n");
23582359

2359-
#ifdef AMGX_WITH_MPI
23602360
amgx_distributed_output(deprecated.c_str(), deprecated.length());
2361-
#else
2362-
amgx_output(deprecated.c_str(), deprecated.length());
2363-
#endif
2361+
23642362
return AMGX_RC_OK;
23652363
}
23662364

@@ -2385,11 +2383,9 @@ extern "C" {
23852383
AMGX_RC AMGX_API AMGX_finalize_plugins()
23862384
{
23872385
std::string deprecated("The AMGX_finalize_plugins API call is deprecated and can be safely removed.\n");
2388-
#ifdef AMGX_WITH_MPI
2386+
23892387
amgx_distributed_output(deprecated.c_str(), deprecated.length());
2390-
#else
2391-
amgx_output(deprecated.c_str(), deprecated.length());
2392-
#endif
2388+
23932389
return AMGX_RC_OK;
23942390
}
23952391

@@ -5234,6 +5230,59 @@ extern "C" {
52345230
return AMGX_RC_OK;
52355231
}
52365232

5233+
AMGX_RC AMGX_matrix_check_symmetry(const AMGX_matrix_handle mtx, int* structurally_symmetric, int* symmetric)
5234+
{
5235+
nvtxRange nvrf(__func__);
5236+
5237+
Resources *resources = NULL;
5238+
AMGX_CHECK_API_ERROR(getAMGXerror(getResourcesFromMatrixHandle(mtx, &resources)), NULL)
5239+
5240+
#ifdef AMGX_WITH_MPI
5241+
int nranks;
5242+
MPI_Comm_size(MPI_COMM_WORLD, &nranks);
5243+
if(nranks > 1) {
5244+
std::string err_msg("AMGX_matrix_check_symmetry cannot yet test distributed matrices, please run on 1 rank.\n");
5245+
amgx_distributed_output(err_msg.c_str(), err_msg.length());
5246+
AMGX_CHECK_API_ERROR(AMGX_ERR_BAD_PARAMETERS, resources); //return AMGX_RC_BAD_PARAMETERS;
5247+
}
5248+
#endif
5249+
5250+
AMGX_ERROR rc = AMGX_OK;
5251+
5252+
AMGX_TRIES()
5253+
{
5254+
AMGX_Mode mode = get_mode_from(mtx);
5255+
5256+
switch (mode)
5257+
{
5258+
#define AMGX_CASE_LINE(CASE) case CASE: { \
5259+
typedef typename TemplateMode<CASE>::Type TConfig; \
5260+
typedef CWrapHandle<AMGX_matrix_handle, Matrix<TConfig>> MatrixW; \
5261+
MatrixW wrapA(mtx); \
5262+
Matrix<TConfig>& A = *wrapA.wrapped(); \
5263+
MatrixAnalysis<TConfig> m_ana(&A); \
5264+
bool verbose = false; \
5265+
bool structurally_symmetric_out = false; \
5266+
bool symmetric_out = false; \
5267+
m_ana.checkSymmetry(structurally_symmetric_out, symmetric_out, verbose); \
5268+
*structurally_symmetric = (structurally_symmetric_out ? 1 : 0); \
5269+
*symmetric = (symmetric_out ? 1 : 0); \
5270+
break; \
5271+
}
5272+
AMGX_FORALL_BUILDS(AMGX_CASE_LINE)
5273+
AMGX_FORCOMPLEX_BUILDS(AMGX_CASE_LINE)
5274+
#undef AMGX_CASE_LINE
5275+
5276+
default:
5277+
return AMGX_RC_BAD_MODE;
5278+
}
5279+
}
5280+
5281+
AMGX_CATCHES(rc)
5282+
AMGX_CHECK_API_ERROR(rc, resources)
5283+
return AMGX_RC_OK;
5284+
}
5285+
52375286
int AMGX_Debug_get_resource_count(AMGX_resources_handle rsc)
52385287
{
52395288
return ((ResourceW *)rsc)->wrapped().use_count();

src/matrix_analysis.cu

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,74 @@ void MatrixAnalysis<T_Config>::checkSymmetry(bool &structuralSymmetric, bool &sy
134134

135135
if (TConfig::memSpace == AMGX_device)
136136
{
137-
FatalError("Device version not implemented", AMGX_ERR_NOT_IMPLEMENTED);
137+
// choose epsilon
138+
double eps = 1e-12;
139+
140+
if (types::PODTypes<ValueTypeA>::vec_prec == AMGX_vecFloat)
141+
{
142+
eps = 1e-7;
143+
}
144+
145+
const int bx = A->get_block_dimx();
146+
const int by = A->get_block_dimy();
147+
const int nnz = A->get_num_nz();
148+
149+
amgx::thrust::device_vector<bool> symm_d(1, true);
150+
amgx::thrust::device_vector<bool> struct_symm_d(1, true);
151+
auto* symmetric_d = amgx::thrust::raw_pointer_cast(symm_d.data());
152+
auto* structurally_symmetric_d = amgx::thrust::raw_pointer_cast(struct_symm_d.data());
153+
auto* col_indices = A->col_indices.raw();
154+
auto* row_offsets = A->row_offsets.raw();
155+
auto* values = A->values.raw();
156+
157+
amgx::thrust::for_each_n(thrust::device, amgx::thrust::counting_iterator<int>(0), A->get_num_rows(), [=] __device__ (int i)
158+
{
159+
for (int jj = row_offsets[i]; jj < row_offsets[i + 1]; jj++)
160+
{
161+
// check structure exists
162+
int j = col_indices[jj];
163+
164+
// ignore diagonal
165+
if (i == j) { continue; }
166+
167+
// loop over row j, search for column i
168+
bool found_on_row = false;
169+
170+
for (int kk = row_offsets[j]; kk < row_offsets[j + 1]; kk++)
171+
{
172+
int k = col_indices[kk];
173+
174+
if (k == i)
175+
{
176+
found_on_row = true;
177+
178+
// check values
179+
// check all elements
180+
const int blocksize = bx * by;
181+
182+
for (int m = 0; m < bx * by; m++)
183+
{
184+
if (types::util<ValueTypeA>::abs(values[jj * blocksize + m] - values[kk * blocksize + m]) > eps)
185+
{
186+
symmetric_d[0] = false;
187+
}
188+
}
189+
190+
break;
191+
}
192+
}
193+
194+
// if we didn't find the element, non-symmetric
195+
if (!found_on_row)
196+
{
197+
structurally_symmetric_d[0] = false;
198+
symmetric_d[0] = false;
199+
}
200+
}
201+
});
202+
203+
symmetric = symm_d[0];
204+
structuralSymmetric = struct_symm_d[0];
138205
}
139206
else if (TConfig::memSpace == AMGX_host)
140207
{

0 commit comments

Comments
 (0)