Skip to content

Commit a30cbed

Browse files
committed
Improvements based on copilot review
Signed-off-by: Brian Kelley <bmkelle@sandia.gov>
1 parent dfde216 commit a30cbed

6 files changed

Lines changed: 44 additions & 38 deletions

File tree

docs/source/API/sparse/spgemm_numeric.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Parameters
5050
For all parameters that are shared with ``spgemm_symbolic`` (dimensions, row maps, entries and matrices), the parameters to ``spgemm_numeric`` must match what was previously passed into ``spgemm_symbolic``
5151
with the same handle. For example, it is not valid to call ``spgemm_symbolic`` with one version of ``entriesA``, and then call ``spgemm_numeric`` with a different ``entriesA`` but the same handle.
5252

53-
:handle: KokkosKernelsHandle with an active spgemm subhandle (i.e. `create_spgem_handle(...)` was previously called on it). Must be the same handle that was previously passed into ``spgemm_symbolic`` with the same input matrices.
53+
:handle: KokkosKernelsHandle with an active spgemm subhandle (i.e. `create_spgemm_handle(...)` was previously called on it). Must be the same handle that was previously passed into ``spgemm_symbolic`` with the same input matrices.
5454

5555
:m, n, k: dimensions of the matrices. **m** is the number of rows in ``A`` and ``C``. **n** is the number of columns in ``A`` and the number of rows in ``B``. **k** is the number of columns in ``B`` and ``C``.
5656

docs/source/API/sparse/spgemm_symbolic.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ After ``spgemm_symbolic`` returns, the number of non-zeros in C is available thr
4444
Parameters
4545
==========
4646

47-
:handle: KokkosKernelsHandle with an active spgemm subhandle (i.e. `create_spgem_handle(...)` was previously called on it).
47+
:handle: KokkosKernelsHandle with an active spgemm subhandle (i.e. `create_spgemm_handle(...)` was previously called on it).
4848

4949
:m, n, k: dimensions of the matrices. **m** is the number of rows in ``A`` and ``C``. **n** is the number of columns in ``A`` and the number of rows in ``B``. **k** is the number of columns in ``B`` and ``C``.
5050

sparse/src/KokkosSparse_spgemm_handle.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,7 @@ class SPGEMMHandle {
518518
* \param alg the SpGEMM algorithm to use.
519519
* \param input_sorted_ whether inputs A and B are sorted.
520520
* Defaults to false for backwards compatibility.
521-
* \param result_sorted_ whether the output matrix C are required to
522-
* be sorted (ascending by column index).
521+
* \param result_sorted_ whether the output matrix C is required to be sorted.
523522
* Defaults to true to maintain backwards compatibility.
524523
*/
525524
SPGEMMHandle(SPGEMMAlgorithm alg = SPGEMM_DEFAULT, bool input_sorted_ = false, bool result_sorted_ = true)

sparse/tpls/KokkosSparse_spgemm_noreuse_tpl_spec_decl.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ SPGEMM_NOREUSE_DECL_CUSPARSE_S(Kokkos::complex<double>)
152152

153153
#ifdef KOKKOSKERNELS_ENABLE_TPL_MKL
154154
template <typename Matrix, typename MatrixConst>
155-
Matrix spgemm_noreuse_mkl(const MatrixConst &A, const MatrixConst &B) {
155+
Matrix spgemm_noreuse_mkl(const MatrixConst &A, const MatrixConst &B, bool result_sorted) {
156156
using size_type = typename Matrix::non_const_size_type;
157157
using index_type = typename Matrix::non_const_ordinal_type;
158158
using scalar_type = typename Matrix::non_const_value_type;
@@ -171,7 +171,9 @@ Matrix spgemm_noreuse_mkl(const MatrixConst &A, const MatrixConst &B) {
171171
generalDescr.mode = SPARSE_FILL_MODE_FULL;
172172
generalDescr.diag = SPARSE_DIAG_NON_UNIT;
173173
KOKKOSKERNELS_MKL_SAFE_CALL(mkl_sparse_spmm(SPARSE_OPERATION_NON_TRANSPOSE, Amkl, Bmkl, &C));
174-
KOKKOSKERNELS_MKL_SAFE_CALL(mkl_sparse_order(C));
174+
if (result_sorted) {
175+
KOKKOSKERNELS_MKL_SAFE_CALL(mkl_sparse_order(C));
176+
}
175177
MKLMatrix wrappedC(C);
176178
MKL_INT nrows = 0, ncols = 0;
177179
MKL_INT *rowmapRaw = nullptr;
@@ -216,10 +218,10 @@ Matrix spgemm_noreuse_mkl(const MatrixConst &A, const MatrixConst &B) {
216218
Kokkos::MemoryTraits<Kokkos::Unmanaged>, const MKL_INT>; \
217219
static KokkosSparse::CrsMatrix<SCALAR, MKL_INT, Kokkos::Device<EXEC, Kokkos::HostSpace>, void, MKL_INT> \
218220
spgemm_noreuse(KokkosSparse::SPGEMMAlgorithm, const ConstMatrix &A, bool, const ConstMatrix &B, bool, bool, \
219-
bool) { \
221+
bool result_sorted) { \
220222
std::string label = "KokkosSparse::spgemm_noreuse[TPL_MKL," + KokkosKernels::ArithTraits<SCALAR>::name() + "]"; \
221223
Kokkos::Profiling::pushRegion(label); \
222-
Matrix C = spgemm_noreuse_mkl<Matrix>(A, B); \
224+
Matrix C = spgemm_noreuse_mkl<Matrix>(A, B, result_sorted); \
223225
Kokkos::Profiling::popRegion(); \
224226
return C; \
225227
} \

sparse/unit_test/Test_Sparse_Utils.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ vector_t create_random_y_vector_mv(crsMat_t crsMat, vector_t x_vector) {
2323
return y_vector;
2424
}
2525

26+
// Test whether two CRS matrices are identical (shape, #nonzeros, entries, and values to within tolerance),
27+
// including the order of entries within each row.
2628
template <typename crsMat_t, typename device>
2729
bool is_same_matrix(crsMat_t output_mat_actual, crsMat_t output_mat_reference) {
2830
typedef typename crsMat_t::StaticCrsGraphType graph_t;

sparse/unit_test/Test_Sparse_spgemm.hpp

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,14 @@ void randomize_matrix_values(const Values &v) {
5656
}
5757

5858
template <typename crsMat_t>
59-
void run_spgemm_noreuse(KokkosSparse::SPGEMMAlgorithm algo, crsMat_t A, crsMat_t B, crsMat_t &C) {
60-
C = KokkosSparse::spgemm<crsMat_t>(algo, A, false, B, false);
59+
void run_spgemm_noreuse(KokkosSparse::SPGEMMAlgorithm algo, crsMat_t A, crsMat_t B, crsMat_t &C, bool input_sorted,
60+
bool result_sorted) {
61+
C = KokkosSparse::spgemm<crsMat_t>(algo, A, false, B, false, input_sorted, result_sorted);
6162
}
6263

6364
template <typename crsMat_t, typename device>
64-
int run_spgemm(crsMat_t &A, crsMat_t &B, KokkosSparse::SPGEMMAlgorithm spgemm_algorithm, crsMat_t &C, bool testReuse) {
65+
int run_spgemm(crsMat_t &A, crsMat_t &B, KokkosSparse::SPGEMMAlgorithm spgemm_algorithm, crsMat_t &C, bool testReuse,
66+
bool input_sorted, bool result_sorted) {
6567
typedef typename crsMat_t::size_type size_type;
6668
typedef typename crsMat_t::ordinal_type lno_t;
6769
typedef typename crsMat_t::value_type scalar_t;
@@ -75,7 +77,7 @@ int run_spgemm(crsMat_t &A, crsMat_t &B, KokkosSparse::SPGEMMAlgorithm spgemm_al
7577
kh.set_team_work_size(16);
7678
kh.set_dynamic_scheduling(true);
7779

78-
kh.create_spgemm_handle(spgemm_algorithm);
80+
kh.create_spgemm_handle(spgemm_algorithm, input_sorted, result_sorted);
7981
{
8082
auto sh = kh.get_spgemm_handle();
8183

@@ -112,7 +114,7 @@ int run_spgemm(crsMat_t &A, crsMat_t &B, KokkosSparse::SPGEMMAlgorithm spgemm_al
112114

113115
template <typename crsMat_t, typename device>
114116
int run_spgemm_old_interface(crsMat_t &A, crsMat_t &B, KokkosSparse::SPGEMMAlgorithm spgemm_algorithm, crsMat_t &result,
115-
bool testReuse) {
117+
bool testReuse, bool input_sorted, bool result_sorted) {
116118
typedef typename crsMat_t::StaticCrsGraphType graph_t;
117119
typedef typename graph_t::row_map_type::non_const_type lno_view_t;
118120
typedef typename graph_t::entries_type::non_const_type lno_nnz_view_t;
@@ -130,7 +132,7 @@ int run_spgemm_old_interface(crsMat_t &A, crsMat_t &B, KokkosSparse::SPGEMMAlgor
130132
kh.set_team_work_size(16);
131133
kh.set_dynamic_scheduling(true);
132134

133-
kh.create_spgemm_handle(spgemm_algorithm);
135+
kh.create_spgemm_handle(spgemm_algorithm, input_sorted, result_sorted);
134136
{
135137
auto sh = kh.get_spgemm_handle();
136138

@@ -197,14 +199,8 @@ void test_spgemm(lno_t m, lno_t k, lno_t n, size_type nnz, lno_t bandwidth, lno_
197199
}
198200
#endif // KOKKOSKERNELS_ENABLE_TPL_ARMPL
199201
using namespace Test;
200-
// device::execution_space::initialize();
201-
// device::execution_space::print_configuration(std::cout);
202202

203203
typedef CrsMatrix<scalar_t, lno_t, device, void, size_type> crsMat_t;
204-
// typedef typename crsMat_t::StaticCrsGraphType graph_t;
205-
// typedef typename graph_t::row_map_type::non_const_type lno_view_t;
206-
// typedef typename graph_t::entries_type::non_const_type lno_nnz_view_t;
207-
// typedef typename crsMat_t::values_type::non_const_type scalar_view_t;
208204

209205
// Generate random compressed sparse row matrix. Randomly generated (non-zero)
210206
// values are stored in a 1-D (1 rank) array.
@@ -220,7 +216,8 @@ void test_spgemm(lno_t m, lno_t k, lno_t n, size_type nnz, lno_t bandwidth, lno_
220216
// If this test won't reuse symbolic, we can compute the reference matrix once
221217
// here
222218
if (!testReuse) {
223-
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, output_mat2, false);
219+
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, output_mat2, /* testReuse */ false, /* input sorted */ true,
220+
/* result sorted */ true);
224221
}
225222

226223
std::vector<SPGEMMAlgorithm> algorithms;
@@ -280,12 +277,16 @@ void test_spgemm(lno_t m, lno_t k, lno_t n, size_type nnz, lno_t bandwidth, lno_
280277
try {
281278
switch (callMode) {
282279
case spgemm_reuse_view:
283-
res = run_spgemm_old_interface<crsMat_t, device>(A, B, spgemm_algorithm, output_mat, testReuse);
280+
res = run_spgemm_old_interface<crsMat_t, device>(A, B, spgemm_algorithm, output_mat, testReuse,
281+
/* input sorted */ true, /* result sorted */ true);
284282
break;
285283
case spgemm_reuse_matrix:
286-
res = run_spgemm<crsMat_t, device>(A, B, spgemm_algorithm, output_mat, testReuse);
284+
res = run_spgemm<crsMat_t, device>(A, B, spgemm_algorithm, output_mat, testReuse, /* input sorted */ true,
285+
/* result sorted */ true);
286+
break;
287+
case spgemm_noreuse:
288+
run_spgemm_noreuse(spgemm_algorithm, A, B, output_mat, /* input sorted */ true, /* result sorted */ true);
287289
break;
288-
case spgemm_noreuse: run_spgemm_noreuse(spgemm_algorithm, A, B, output_mat); break;
289290
}
290291
} catch (const char *message) {
291292
EXPECT_TRUE(is_expected_to_fail) << algo << ": " << message;
@@ -302,7 +303,8 @@ void test_spgemm(lno_t m, lno_t k, lno_t n, size_type nnz, lno_t bandwidth, lno_
302303
// If this is testing reuse, the values of A and B changed so
303304
// the reference matrix must be recomputed
304305
if (testReuse) {
305-
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, output_mat2, false);
306+
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, output_mat2, /* reuse */ false, /* input sorted */ true,
307+
/* result sorted */ true);
306308
}
307309

308310
// double spgemm_time = timer1.seconds();
@@ -315,12 +317,8 @@ void test_spgemm(lno_t m, lno_t k, lno_t n, size_type nnz, lno_t bandwidth, lno_
315317
<< ", testReuse=" << int(testReuse) << ", m=" << m << ", k=" << k << ", n=" << n
316318
<< ", nnz=" << nnz << ", bandwidth=" << bandwidth
317319
<< ", row_size_variance=" << row_size_variance;
318-
// EXPECT_TRUE( equal) << algo;
319320
}
320-
// std::cout << "algo:" << algo << " spgemm_time:" << spgemm_time << "
321-
// output_check_time:" << timer1.seconds() << std::endl;
322321
}
323-
// device::execution_space::finalize();
324322
}
325323

326324
template <typename scalar_t, typename lno_t, typename size_type, typename device>
@@ -358,14 +356,17 @@ void test_spgemm_symbolic(bool callSymbolicFirst, bool testEmpty) {
358356
KokkosSparse::sort_crs_matrix(B);
359357
}
360358
// Call reference impl to get complete product
359+
// Note: for both reference C and output C: we're only checking that
360+
// the rowmap is correct, so don't care if result is sorted.
361361
crsMat_t C_reference;
362-
Test::run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, C_reference, false);
362+
Test::run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, C_reference, /* reuse */ false, /* input sorted */ true,
363+
/* result sorted */ false);
363364
// Now call just symbolic, and specifically request that rowptrs be populated
364365
// Make sure this never depends on C_rowmap being initialized
365366
rowmap_t C_rowmap(Kokkos::view_alloc(Kokkos::WithoutInitializing, "rowmapC"), m + 1);
366367
Kokkos::deep_copy(C_rowmap, size_type(123));
367368
KernelHandle kh;
368-
kh.create_spgemm_handle();
369+
kh.create_spgemm_handle(KokkosSparse::SPGEMM_DEFAULT, /* input sorted */ true, /* output sorted */ false);
369370
if (callSymbolicFirst) {
370371
KokkosSparse::spgemm_symbolic(&kh, m, n, k, A.graph.row_map, A.graph.entries, false, B.graph.row_map,
371372
B.graph.entries, false, C_rowmap);
@@ -430,12 +431,14 @@ void test_issue402() {
430431
KokkosSparse::sort_crs_matrix(A);
431432
KokkosSparse::sort_crs_matrix(B);
432433
crsMat_t Cgold;
433-
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, Cgold, false);
434+
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, Cgold, /* reuse */ false, /* input sorted */ true,
435+
/* result sorted */ true);
434436
crsMat_t C;
435437
bool success = true;
436438
std::string errMsg;
437439
try {
438-
int res = run_spgemm<crsMat_t, device>(A, B, SPGEMM_KK_MEMORY, C, false);
440+
int res = run_spgemm<crsMat_t, device>(A, B, SPGEMM_KK_MEMORY, C, /* reuse */ false, /* input sorted */ true,
441+
/* result sorted */ true);
439442
if (res) throw "run_spgemm returned error code";
440443
} catch (const char *message) {
441444
errMsg = message;
@@ -520,18 +523,18 @@ void test_spgemm_sortedness() {
520523
const lno_t bandwidth = 500;
521524
const lno_t row_size_variance = 10;
522525

523-
// Generate random matrices. This relies on kk_generate_sparse_matrix not producing a sorted matrix.
526+
// Generate random matrices. This relies on kk_generate_sparse_matrix NOT producing a sorted matrix.
524527
crsMat_t A = KokkosSparse::Impl::kk_generate_sparse_matrix<crsMat_t>(m, k, nnz, row_size_variance, bandwidth);
525528
crsMat_t B = KokkosSparse::Impl::kk_generate_sparse_matrix<crsMat_t>(k, n, nnz, row_size_variance, bandwidth);
526529
randomize_matrix_values(A.values);
527530
randomize_matrix_values(B.values);
528531

529532
// Compute reference C using the serial/debug algorithm.
530533
crsMat_t C_reference;
531-
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, C_reference, false);
534+
run_spgemm<crsMat_t, device>(A, B, SPGEMM_DEBUG, C_reference, /* reuse */ false, /* input sorted */ false,
535+
/* result sorted */ true);
532536

533537
std::vector<std::string> algorithm_names = {"SPGEMM_DEFAULT", "SPGEMM_KK"};
534-
std::vector<SPGEMMAlgorithm> algorithms = {SPGEMM_DEFAULT, SPGEMM_KK};
535538
for (auto algo_name : algorithm_names) {
536539
SPGEMMAlgorithm algo = KokkosSparse::StringToSPGEMMAlgorithm(algo_name);
537540
for (bool resultSorted : {true, false}) {
@@ -560,7 +563,7 @@ void test_spgemm_sortedness() {
560563
kh.destroy_spgemm_handle();
561564
C = crsMat_t("C", num_rows_A, num_cols_B, c_nnz_size, valuesC, row_mapC, entriesC);
562565
} else {
563-
run_spgemm_noreuse(algo, A, B, C);
566+
run_spgemm_noreuse(algo, A, B, C, /* input sorted */ false, /* result sorted */ resultSorted);
564567
}
565568

566569
// If we requested sorted output, verify the output really is sorted.
@@ -570,7 +573,7 @@ void test_spgemm_sortedness() {
570573
<< " produced unsorted output for algo " << algo_name
571574
<< " even though sorted output was requested";
572575
} else {
573-
// Sort C for comparison
576+
// Sort C so we can directly compare it to sorted reference
574577
KokkosSparse::sort_crs_matrix(C);
575578
}
576579

0 commit comments

Comments
 (0)