From 61185b4c0ab14f5b22b8630693e545411811fb4f Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Fri, 30 May 2025 14:23:34 -0400 Subject: [PATCH 01/16] set up sparse tests with constructor, set pointers, and allocate and destroy memory --- tests/unit/matrix/CMakeLists.txt | 7 +- tests/unit/matrix/SparseTests.hpp | 136 +++++++++++++++++++++++++++ tests/unit/matrix/runSparseTests.cpp | 51 ++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 tests/unit/matrix/SparseTests.hpp create mode 100644 tests/unit/matrix/runSparseTests.cpp diff --git a/tests/unit/matrix/CMakeLists.txt b/tests/unit/matrix/CMakeLists.txt index 85d3a9af0..656de380f 100644 --- a/tests/unit/matrix/CMakeLists.txt +++ b/tests/unit/matrix/CMakeLists.txt @@ -10,6 +10,10 @@ add_executable(runMatrixIoTests.exe runMatrixIoTests.cpp) target_link_libraries(runMatrixIoTests.exe PRIVATE ReSolve resolve_matrix) +# Build sparse matrix tests +add_executable(runSparseTests.exe runSparseTests.cpp) +target_link_libraries(runSparseTests.exe PRIVATE ReSolve resolve_matrix) + # Build matrix handler tests add_executable(runMatrixHandlerTests.exe runMatrixHandlerTests.cpp) target_link_libraries(runMatrixHandlerTests.exe PRIVATE ReSolve resolve_matrix) @@ -25,7 +29,7 @@ if(RESOLVE_USE_LUSOL) endif() # Install tests -set(installable_tests runMatrixIoTests.exe runMatrixHandlerTests.exe runMatrixFactorizationTests.exe) +set(installable_tests runMatrixIoTests.exe runMatrixHandlerTests.exe runMatrixFactorizationTests.exe runSparseTests.exe) if(RESOLVE_USE_LUSOL) list(APPEND installable_tests runLUSOLTests.exe) endif() @@ -35,6 +39,7 @@ install(TARGETS ${installable_tests} add_test(NAME matrix_test COMMAND $) add_test(NAME matrix_handler_test COMMAND $) add_test(NAME matrix_factorization_test COMMAND $) +add_test(NAME sparse_matrix_test COMMAND $) if(RESOLVE_USE_LUSOL) add_test(NAME lusol_factorization_test COMMAND $) endif() diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp new file mode 100644 index 000000000..ee15fc348 --- /dev/null +++ b/tests/unit/matrix/SparseTests.hpp @@ -0,0 +1,136 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ReSolve { namespace tests { + class SparseTests : TestBase + { + public: + SparseTests(ReSolve::MatrixHandler& handler) : handler_(handler) + { + if (handler_.getIsCudaEnabled() || handler_.getIsHipEnabled()) { + memspace_ = memory::DEVICE; + } else { + memspace_ = memory::HOST; + } + } + + ~SparseTests() + { + } + + /** + * @brief Constructor test for sparse matrix + * + * Constructs a CSR matrix with the given parameters and confirms that the + * parameters are stored correctly. + * + * @param[in] n - number of rows + * @param[in] m - number of columns + * @param[in] nnz - number of non-zeros + * @param[in] is_symmetric - true if the matrix is symmetric, false otherwise + * @param[in] is_expanded - true if the matrix is expanded, false otherwise + * + * @return TestOutcome indicating success or failure of the test + */ + TestOutcome constructor(index_type n, + index_type m, + index_type nnz, + bool is_symmetric = false, + bool is_expanded = true) + { + TestStatus status; + status = true; + + // Create a sparse matrix with 3 rows, 4 columns and 5 non-zeros + ReSolve::matrix::Csr A(n, m, nnz, is_symmetric, is_expanded); + + // Check if the matrix was created correctly + if (A.getNumRows() != n || A.getNumColumns() != m || A.getNnz() != nnz) { + std::cout << "Matrix dimensions do not match expected values.\n"; + status = false; + } + + return status.report(__func__); + } + + /** + * @brief Test set data pointers for the sparse matrix + * + * Sets the row, column, and value data pointers for the sparse matrix and + * checks if the pointers are set correctly. + * + * @return TestOutcome indicating success or failure of the test + */ + TestOutcome setDataPointers() + { + TestStatus status; + status = true; + + // Create a sparse matrix with 3 rows, 4 columns and 5 non-zeros + ReSolve::matrix::Csr A(3, 4, 5); + + // Set data pointers + index_type* row_data = new index_type[4]{0, 2, 4, 5}; + index_type* col_data = new index_type[5]{0, 1, 2, 3, 1}; + real_type* val_data = new real_type[5]{1.0, 2.0, 3.0, 4.0, 5.0}; + + if (A.setDataPointers(row_data, col_data, val_data, memspace_) != 0) { + std::cout << "Failed to set data pointers.\n"; + status = false; + } else if (A.getRowData(memspace_) != row_data || + A.getColData(memspace_) != col_data || + A.getValues(memspace_) != val_data) { + std::cout << "Data pointers do not point to expected values.\n"; + status = false; + } + + return status.report(__func__); + } + + /** + * @brief Test allocating and destroying matrix data + * + * Allocates memory for the sparse matrix data and checks if the pointers + * are not null after allocation. Then destroys the allocated data. + * + * @param[in] n - number of rows + * @param[in] m - number of columns + * @param[in] nnz - number of non-zeros + * + * @return TestOutcome indicating success or failure of the test + */ + TestOutcome allocateAndDestroyData(index_type n, index_type m, index_type nnz) + { + TestStatus status; + status = true; + + ReSolve::matrix::Csr A(n, m, nnz); + + if (A.allocateMatrixData(memspace_) != 0) { + std::cout << "Failed to allocate matrix data.\n"; + status = false; + } else if (A.getRowData(memspace_) == nullptr || + A.getColData(memspace_) == nullptr || + A.getValues(memspace_) == nullptr) { + std::cout << "Matrix data pointers are null after allocation.\n"; + status = false; + } + + A.destroyMatrixData(memspace_); + + return status.report(__func__); + } + + private: + ReSolve::MatrixHandler& handler_; + memory::MemorySpace memspace_; + }; // class SparseTests +}} // namespace ReSolve::tests \ No newline at end of file diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp new file mode 100644 index 000000000..c8b9d3d69 --- /dev/null +++ b/tests/unit/matrix/runSparseTests.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +#include +#include +#include "SparseTests.hpp" + +/** + * @brief Run sparse matrix tests with a given backend + * + * @tparam WorkspaceType workspace type LinAlgWorkspace{Cpu, CUDA, HIP} supported + * @param[in] backend - name of the hardware backend + * @param[out] result - test results + */ +template +void runTests(const std::string& backend, ReSolve::tests::TestingResults& result) +{ + std::cout << "Running tests on " << backend << " device:\n"; + + WorkspaceType workspace; + workspace.initializeHandles(); + ReSolve::MatrixHandler handler(&workspace); + + ReSolve::tests::SparseTests test(handler); + + result += test.constructor(50, 50, 10); + result += test.constructor(50, 50, 10, true); + result += test.constructor(50, 50, 10, false, false); + + result += test.setDataPointers(); + + result += test.allocateAndDestroyData(50, 50, 10); +} + +int main(int, char**) +{ + ReSolve::tests::TestingResults result; + runTests("CPU", result); + +#ifdef RESOLVE_USE_CUDA + runTests("CUDA", result); +#endif + +#ifdef RESOLVE_USE_HIP + runTests("HIP", result); +#endif + + return result.summary(); +} \ No newline at end of file From cf8c72839e23286f1edbe8b4e8c0d82af7c39ef2 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Mon, 2 Jun 2025 09:07:02 -0400 Subject: [PATCH 02/16] parameterize tests for setting funcs --- tests/unit/matrix/SparseTests.hpp | 57 +++++++++++++++++++++++----- tests/unit/matrix/runSparseTests.cpp | 11 +++--- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index ee15fc348..17fd73b12 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -8,6 +8,7 @@ #include #include #include +#include namespace ReSolve { namespace tests { class SparseTests : TestBase @@ -49,10 +50,8 @@ namespace ReSolve { namespace tests { TestStatus status; status = true; - // Create a sparse matrix with 3 rows, 4 columns and 5 non-zeros ReSolve::matrix::Csr A(n, m, nnz, is_symmetric, is_expanded); - // Check if the matrix was created correctly if (A.getNumRows() != n || A.getNumColumns() != m || A.getNnz() != nnz) { std::cout << "Matrix dimensions do not match expected values.\n"; status = false; @@ -69,18 +68,27 @@ namespace ReSolve { namespace tests { * * @return TestOutcome indicating success or failure of the test */ - TestOutcome setDataPointers() + TestOutcome setDataPointers(index_type n, index_type m, index_type nnz) { + assert(nnz % m == 0 && "For this test, nnz must be divisible by m"); + TestStatus status; status = true; - // Create a sparse matrix with 3 rows, 4 columns and 5 non-zeros - ReSolve::matrix::Csr A(3, 4, 5); + ReSolve::matrix::Csr A(n, m, nnz); - // Set data pointers - index_type* row_data = new index_type[4]{0, 2, 4, 5}; - index_type* col_data = new index_type[5]{0, 1, 2, 3, 1}; - real_type* val_data = new real_type[5]{1.0, 2.0, 3.0, 4.0, 5.0}; + index_type* row_data = new index_type[n + 1]; + for (index_type i = 0; i <= n; ++i) { + row_data[i] = i * (nnz / n); // Simple pattern for row pointers + } + index_type* col_data = new index_type[nnz]; + for (index_type i = 0; i < nnz; ++i) { + col_data[i] = i % m; // Simple pattern for column indices + } + real_type* val_data = new real_type[nnz]; + for (index_type i = 0; i < nnz; ++i) { + val_data[i] = static_cast(i + 1); + } if (A.setDataPointers(row_data, col_data, val_data, memspace_) != 0) { std::cout << "Failed to set data pointers.\n"; @@ -95,6 +103,37 @@ namespace ReSolve { namespace tests { return status.report(__func__); } + /** + * @brief Test setting values pointer for the sparse matrix + * + * Sets the values pointer for the sparse matrix and checks if the pointer + * points to the expected values. + * + * @return TestOutcome indicating success or failure of the test + */ + TestOutcome setValuesPointer(index_type n, index_type m, index_type nnz) + { + TestStatus status; + status = true; + + ReSolve::matrix::Csr A(n, m, nnz); + + real_type* val_data = new real_type[nnz]; + for (index_type i = 0; i < nnz; ++i) { + val_data[i] = static_cast(i + 1); + } + + if (A.setValuesPointer(val_data, memspace_) != 0) { + std::cout << "Failed to set values pointer.\n"; + status = false; + } else if (A.getValues(memspace_) != val_data) { + std::cout << "Values pointer does not point to expected values.\n"; + status = false; + } + + return status.report(__func__); + } + /** * @brief Test allocating and destroying matrix data * diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp index c8b9d3d69..1c51b921c 100644 --- a/tests/unit/matrix/runSparseTests.cpp +++ b/tests/unit/matrix/runSparseTests.cpp @@ -25,13 +25,14 @@ void runTests(const std::string& backend, ReSolve::tests::TestingResults& result ReSolve::tests::SparseTests test(handler); - result += test.constructor(50, 50, 10); - result += test.constructor(50, 50, 10, true); - result += test.constructor(50, 50, 10, false, false); + result += test.constructor(50, 50, 100); + result += test.constructor(50, 50, 100, true); + result += test.constructor(50, 50, 100, false, false); - result += test.setDataPointers(); + result += test.setDataPointers(50, 50, 100); + result += test.setValuesPointer(50, 50, 100); - result += test.allocateAndDestroyData(50, 50, 10); + result += test.allocateAndDestroyData(50, 50, 100); } int main(int, char**) From 46a494a41dac7002b762746a486003940205bfdc Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Mon, 2 Jun 2025 09:32:28 -0400 Subject: [PATCH 03/16] test copy function and clean up --- tests/unit/matrix/SparseTests.hpp | 173 ++++++++++++++++++++++++++- tests/unit/matrix/runSparseTests.cpp | 4 + 2 files changed, 175 insertions(+), 2 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index 17fd73b12..a4a2aef59 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -66,6 +66,9 @@ namespace ReSolve { namespace tests { * Sets the row, column, and value data pointers for the sparse matrix and * checks if the pointers are set correctly. * + * @param n - number of rows + * @param m - number of columns + * @param nnz - number of non-zeros * @return TestOutcome indicating success or failure of the test */ TestOutcome setDataPointers(index_type n, index_type m, index_type nnz) @@ -109,6 +112,9 @@ namespace ReSolve { namespace tests { * Sets the values pointer for the sparse matrix and checks if the pointer * points to the expected values. * + * @param n - number of rows + * @param m - number of columns + * @param nnz - number of non-zeros * @return TestOutcome indicating success or failure of the test */ TestOutcome setValuesPointer(index_type n, index_type m, index_type nnz) @@ -131,6 +137,161 @@ namespace ReSolve { namespace tests { status = false; } + // Clean up allocated memory + delete[] val_data; + + return status.report(__func__); + } + + /** + * @brief Test copying values into the sparse matrix + * + * Copies values into the sparse matrix, modifies the original values, + * and verifies the correct unmodified values are stored in the matrix, + * and that the values pointer does not point to the original array. + * + * @param n - number of rows + * @param m - number of columns + * @param nnz - number of non-zeros + * @return TestOutcome indicating success or failure of the test + */ + TestOutcome copyValues(index_type n, index_type m, index_type nnz) + { + TestStatus status; + status = true; + + ReSolve::matrix::Csr A(n, m, nnz); + + real_type* val_data = new real_type[nnz]; + for (index_type i = 0; i < nnz; ++i) { + val_data[i] = static_cast(i + 1); + } + + if (A.copyValues(val_data, memory::HOST, memspace_) != 0) { + std::cout << "Failed to copy values.\n"; + status = false; + } else { + // Modify original values to ensure copy worked + for (index_type i = 0; i < nnz; ++i) { + val_data[i] *= 2; // Change the values + } + + if (A.getValues(memspace_) == nullptr) { + std::cout << "Values pointer is null after copy.\n"; + status = false; + } else if (A.getValues(memspace_) == val_data) { + std::cout << "Values pointer should not point to original array after copy.\n"; + status = false; + } else { + // Check if the copied values are correct + for (index_type i = 0; i < nnz; ++i) { + if (A.getValues(memspace_)[i] != static_cast(i + 1)) { + std::cout << "Copied values do not match expected values.\n"; + status = false; + break; + } + } + } + } + + // Clean up allocated memory + delete[] val_data; + + if (A.destroyMatrixData(memspace_) != 0) { + std::cout << "Failed to destroy matrix data.\n"; + status = false; + } + + return status.report(__func__); + } + + /** + * @brief Verify that matrix will not reset data pointers when it currently owns data. + * + * Copies values into the sparse matrix and then attempts to set the values + * pointer, which should fail since the matrix owns the data. + * + * @param n - number of rows + * @param m - number of columns + * @param nnz - number of non-zeros + * @return TestOutcome indicating success or failure of the test + */ + TestOutcome copyValuesAndSetDataPointers(index_type n, index_type m, index_type nnz) + { + TestStatus status; + status = true; + + ReSolve::matrix::Csr A(n, m, nnz); + + real_type* val_data = new real_type[nnz]; + for (index_type i = 0; i < nnz; ++i) { + val_data[i] = static_cast(i + 1); + } + + if (A.copyValues(val_data, memory::HOST, memspace_) != 0) { + std::cout << "Failed to copy values.\n"; + status = false; + } + + index_type* row_data = new index_type[n + 1]; + for (index_type i = 0; i <= n; ++i) { + row_data[i] = i * (nnz / n); // Simple pattern for row pointers + } + index_type* col_data = new index_type[nnz]; + for (index_type i = 0; i < nnz; ++i) { + col_data[i] = i % m; // Simple pattern for column indices + } + + if (A.setDataPointers(row_data, col_data, val_data, memspace_) == 0 || + A.getRowData(memspace_) == row_data || + A.getColData(memspace_) == col_data || + A.getValues(memspace_) == val_data) { + std::cout << "Should not have set data pointers after copying values.\n"; + status = false; + } + + // Clean up allocated memory + delete[] val_data; + delete[] row_data; + delete[] col_data; + + return status.report(__func__); + } + + /** + * @brief Verify that matrix will not reset values pointer when it currently owns data. + * + * Copies a data array using `copyValues`, then attempts to set the values pointer, + * and verifies that this results in an error. + * + * @return TestOutcome indicating success or failure of the test + */ + TestOutcome copyValuesAndSetValues(index_type n, index_type m, index_type nnz) + { + TestStatus status; + status = true; + + ReSolve::matrix::Csr A(n, m, nnz); + + real_type* val_data = new real_type[nnz]; + for (index_type i = 0; i < nnz; ++i) { + val_data[i] = static_cast(i + 1); + } + + if (A.copyValues(val_data, memory::HOST, memspace_) != 0) { + std::cout << "Failed to copy values.\n"; + status = false; + } + + if (A.setValuesPointer(val_data, memspace_) == 0 || + A.getValues(memspace_) == val_data) { + std::cout << "Should not have set values pointer when matrix owns data.\n"; + status = false; + } + + // Clean up allocated memory + delete[] val_data; + return status.report(__func__); } @@ -163,8 +324,16 @@ namespace ReSolve { namespace tests { status = false; } - A.destroyMatrixData(memspace_); - + if (A.destroyMatrixData(memspace_) != 0) { + std::cout << "Failed to destroy matrix data.\n"; + status = false; + } else if (A.getRowData(memspace_) != nullptr || + A.getColData(memspace_) != nullptr || + A.getValues(memspace_) != nullptr) { + std::cout << "Matrix data pointers are not null after destruction.\n"; + status = false; + } + return status.report(__func__); } diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp index 1c51b921c..6a872ad96 100644 --- a/tests/unit/matrix/runSparseTests.cpp +++ b/tests/unit/matrix/runSparseTests.cpp @@ -32,6 +32,10 @@ void runTests(const std::string& backend, ReSolve::tests::TestingResults& result result += test.setDataPointers(50, 50, 100); result += test.setValuesPointer(50, 50, 100); + result += test.copyValues(50, 50, 100); + result += test.copyValuesAndSetValues(50, 50, 100); + result += test.copyValuesAndSetDataPointers(50, 50, 100); + result += test.allocateAndDestroyData(50, 50, 100); } From e7d4447b48abe33e2aa96ff68ea0c925a4b3985d Mon Sep 17 00:00:00 2001 From: Shaked Regev <35384901+shakedregev@users.noreply.github.com> Date: Mon, 2 Jun 2025 09:49:18 -0400 Subject: [PATCH 04/16] Update tests/unit/matrix/SparseTests.hpp --- tests/unit/matrix/SparseTests.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index a4a2aef59..5b98f1673 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -37,7 +37,8 @@ namespace ReSolve { namespace tests { * @param[in] m - number of columns * @param[in] nnz - number of non-zeros * @param[in] is_symmetric - true if the matrix is symmetric, false otherwise - * @param[in] is_expanded - true if the matrix is expanded, false otherwise + * @param[in] is_expanded - true if the matrix is expanded (all non-zeros + are stored explicitly, not assumed based on symmetry), false otherwise * * @return TestOutcome indicating success or failure of the test */ From e82e402353c4d798c1cfbd8d39f03cab7156ca21 Mon Sep 17 00:00:00 2001 From: Shaked Regev <35384901+shakedregev@users.noreply.github.com> Date: Mon, 2 Jun 2025 09:52:27 -0400 Subject: [PATCH 05/16] Update tests/unit/matrix/SparseTests.hpp --- tests/unit/matrix/SparseTests.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index 5b98f1673..e2f2c3f2b 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -113,9 +113,9 @@ namespace ReSolve { namespace tests { * Sets the values pointer for the sparse matrix and checks if the pointer * points to the expected values. * - * @param n - number of rows - * @param m - number of columns - * @param nnz - number of non-zeros + * @param[in] n - number of rows + * @param[in] m - number of columns + * @param[in] nnz - number of non-zeros * @return TestOutcome indicating success or failure of the test */ TestOutcome setValuesPointer(index_type n, index_type m, index_type nnz) From 8ffaa548954efdb96b8893b47b2573c5b7e02b54 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Mon, 2 Jun 2025 13:41:21 -0400 Subject: [PATCH 06/16] fix setDataPointers test on device --- tests/unit/matrix/SparseTests.hpp | 36 ++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index e2f2c3f2b..e34f2e8ef 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -4,11 +4,12 @@ #include #include #include +#include #include #include #include #include -#include +#include namespace ReSolve { namespace tests { class SparseTests : TestBase @@ -81,17 +82,35 @@ namespace ReSolve { namespace tests { ReSolve::matrix::Csr A(n, m, nnz); - index_type* row_data = new index_type[n + 1]; + index_type* h_row_data = new index_type[n + 1]; for (index_type i = 0; i <= n; ++i) { - row_data[i] = i * (nnz / n); // Simple pattern for row pointers + h_row_data[i] = i * (nnz / n); // Simple pattern for row pointers } - index_type* col_data = new index_type[nnz]; + index_type* h_col_data = new index_type[nnz]; for (index_type i = 0; i < nnz; ++i) { - col_data[i] = i % m; // Simple pattern for column indices + h_col_data[i] = i % m; // Simple pattern for column indices } - real_type* val_data = new real_type[nnz]; + real_type* h_val_data = new real_type[nnz]; for (index_type i = 0; i < nnz; ++i) { - val_data[i] = static_cast(i + 1); + h_val_data[i] = static_cast(i + 1); + } + + // If on device, allocate and copy data + index_type* row_data; + index_type* col_data; + real_type* val_data; + + if (memspace_ == memory::HOST) { + row_data = h_row_data; + col_data = h_col_data; + val_data = h_val_data; + } else { + mem_.allocateArrayOnDevice(&row_data, n + 1); + mem_.allocateArrayOnDevice(&col_data, nnz); + mem_.allocateArrayOnDevice(&val_data, nnz); + mem_.copyArrayHostToDevice(row_data, h_row_data, n + 1); + mem_.copyArrayHostToDevice(col_data, h_col_data, nnz); + mem_.copyArrayHostToDevice(val_data, h_val_data, nnz); } if (A.setDataPointers(row_data, col_data, val_data, memspace_) != 0) { @@ -334,12 +353,13 @@ namespace ReSolve { namespace tests { std::cout << "Matrix data pointers are not null after destruction.\n"; status = false; } - + return status.report(__func__); } private: ReSolve::MatrixHandler& handler_; memory::MemorySpace memspace_; + MemoryHandler mem_; }; // class SparseTests }} // namespace ReSolve::tests \ No newline at end of file From 45640d460fa33c48cc7000295ed481d260356e51 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Mon, 2 Jun 2025 14:24:17 -0400 Subject: [PATCH 07/16] hardcode cpu for setting data tests --- tests/unit/matrix/SparseTests.hpp | 53 ++++++++++--------------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index e34f2e8ef..b46d61715 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -95,30 +95,12 @@ namespace ReSolve { namespace tests { h_val_data[i] = static_cast(i + 1); } - // If on device, allocate and copy data - index_type* row_data; - index_type* col_data; - real_type* val_data; - - if (memspace_ == memory::HOST) { - row_data = h_row_data; - col_data = h_col_data; - val_data = h_val_data; - } else { - mem_.allocateArrayOnDevice(&row_data, n + 1); - mem_.allocateArrayOnDevice(&col_data, nnz); - mem_.allocateArrayOnDevice(&val_data, nnz); - mem_.copyArrayHostToDevice(row_data, h_row_data, n + 1); - mem_.copyArrayHostToDevice(col_data, h_col_data, nnz); - mem_.copyArrayHostToDevice(val_data, h_val_data, nnz); - } - - if (A.setDataPointers(row_data, col_data, val_data, memspace_) != 0) { + if (A.setDataPointers(h_row_data, h_col_data, h_val_data, memory::HOST) != 0) { std::cout << "Failed to set data pointers.\n"; status = false; - } else if (A.getRowData(memspace_) != row_data || - A.getColData(memspace_) != col_data || - A.getValues(memspace_) != val_data) { + } else if (A.getRowData(memory::HOST) != h_row_data || + A.getColData(memory::HOST) != h_col_data || + A.getValues(memory::HOST) != h_val_data) { std::cout << "Data pointers do not point to expected values.\n"; status = false; } @@ -149,17 +131,14 @@ namespace ReSolve { namespace tests { val_data[i] = static_cast(i + 1); } - if (A.setValuesPointer(val_data, memspace_) != 0) { + if (A.setValuesPointer(val_data, memory::HOST) != 0) { std::cout << "Failed to set values pointer.\n"; status = false; - } else if (A.getValues(memspace_) != val_data) { + } else if (A.getValues(memory::HOST) != val_data) { std::cout << "Values pointer does not point to expected values.\n"; status = false; } - // Clean up allocated memory - delete[] val_data; - return status.report(__func__); } @@ -199,13 +178,17 @@ namespace ReSolve { namespace tests { if (A.getValues(memspace_) == nullptr) { std::cout << "Values pointer is null after copy.\n"; status = false; - } else if (A.getValues(memspace_) == val_data) { - std::cout << "Values pointer should not point to original array after copy.\n"; - status = false; } else { + real_type* h_val_data; + if (memspace_ == memory::HOST) { + h_val_data = A.getValues(memory::HOST); + } else { + mem_.copyArrayDeviceToHost(h_val_data, A.getValues(memory::DEVICE), A.getNnz()); + } + // Check if the copied values are correct for (index_type i = 0; i < nnz; ++i) { - if (A.getValues(memspace_)[i] != static_cast(i + 1)) { + if (h_val_data[i] != static_cast(i + 1)) { std::cout << "Copied values do not match expected values.\n"; status = false; break; @@ -262,10 +245,7 @@ namespace ReSolve { namespace tests { col_data[i] = i % m; // Simple pattern for column indices } - if (A.setDataPointers(row_data, col_data, val_data, memspace_) == 0 || - A.getRowData(memspace_) == row_data || - A.getColData(memspace_) == col_data || - A.getValues(memspace_) == val_data) { + if (A.setDataPointers(row_data, col_data, val_data, memory::HOST) == 0) { std::cout << "Should not have set data pointers after copying values.\n"; status = false; } @@ -303,8 +283,7 @@ namespace ReSolve { namespace tests { status = false; } - if (A.setValuesPointer(val_data, memspace_) == 0 || - A.getValues(memspace_) == val_data) { + if (A.setValuesPointer(val_data, memory::HOST) == 0) { std::cout << "Should not have set values pointer when matrix owns data.\n"; status = false; } From 78f34d627d58e67c1388bdda1431867e37e847f6 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Tue, 3 Jun 2025 09:23:55 -0400 Subject: [PATCH 08/16] change matrix objects to pointers --- tests/unit/matrix/SparseTests.hpp | 42 +++++++++++++++---------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index b46d61715..a72d3fbbf 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -159,14 +159,14 @@ namespace ReSolve { namespace tests { TestStatus status; status = true; - ReSolve::matrix::Csr A(n, m, nnz); + ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); real_type* val_data = new real_type[nnz]; for (index_type i = 0; i < nnz; ++i) { val_data[i] = static_cast(i + 1); } - if (A.copyValues(val_data, memory::HOST, memspace_) != 0) { + if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; status = false; } else { @@ -175,15 +175,15 @@ namespace ReSolve { namespace tests { val_data[i] *= 2; // Change the values } - if (A.getValues(memspace_) == nullptr) { + if (A->getValues(memspace_) == nullptr) { std::cout << "Values pointer is null after copy.\n"; status = false; } else { real_type* h_val_data; if (memspace_ == memory::HOST) { - h_val_data = A.getValues(memory::HOST); + h_val_data = A->getValues(memory::HOST); } else { - mem_.copyArrayDeviceToHost(h_val_data, A.getValues(memory::DEVICE), A.getNnz()); + mem_.copyArrayDeviceToHost(h_val_data, A->getValues(memory::DEVICE), nnz); } // Check if the copied values are correct @@ -200,7 +200,7 @@ namespace ReSolve { namespace tests { // Clean up allocated memory delete[] val_data; - if (A.destroyMatrixData(memspace_) != 0) { + if (A->destroyMatrixData(memspace_) != 0) { std::cout << "Failed to destroy matrix data.\n"; status = false; } @@ -224,14 +224,14 @@ namespace ReSolve { namespace tests { TestStatus status; status = true; - ReSolve::matrix::Csr A(n, m, nnz); + ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); real_type* val_data = new real_type[nnz]; for (index_type i = 0; i < nnz; ++i) { val_data[i] = static_cast(i + 1); } - if (A.copyValues(val_data, memory::HOST, memspace_) != 0) { + if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; status = false; } @@ -245,7 +245,7 @@ namespace ReSolve { namespace tests { col_data[i] = i % m; // Simple pattern for column indices } - if (A.setDataPointers(row_data, col_data, val_data, memory::HOST) == 0) { + if (A->setDataPointers(row_data, col_data, val_data, memspace_) == 0) { std::cout << "Should not have set data pointers after copying values.\n"; status = false; } @@ -271,19 +271,19 @@ namespace ReSolve { namespace tests { TestStatus status; status = true; - ReSolve::matrix::Csr A(n, m, nnz); + ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); real_type* val_data = new real_type[nnz]; for (index_type i = 0; i < nnz; ++i) { val_data[i] = static_cast(i + 1); } - if (A.copyValues(val_data, memory::HOST, memspace_) != 0) { + if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; status = false; } - if (A.setValuesPointer(val_data, memory::HOST) == 0) { + if (A->setValuesPointer(val_data, memspace_) == 0) { std::cout << "Should not have set values pointer when matrix owns data.\n"; status = false; } @@ -311,24 +311,24 @@ namespace ReSolve { namespace tests { TestStatus status; status = true; - ReSolve::matrix::Csr A(n, m, nnz); + ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); - if (A.allocateMatrixData(memspace_) != 0) { + if (A->allocateMatrixData(memspace_) != 0) { std::cout << "Failed to allocate matrix data.\n"; status = false; - } else if (A.getRowData(memspace_) == nullptr || - A.getColData(memspace_) == nullptr || - A.getValues(memspace_) == nullptr) { + } else if (A->getRowData(memspace_) == nullptr || + A->getColData(memspace_) == nullptr || + A->getValues(memspace_) == nullptr) { std::cout << "Matrix data pointers are null after allocation.\n"; status = false; } - if (A.destroyMatrixData(memspace_) != 0) { + if (A->destroyMatrixData(memspace_) != 0) { std::cout << "Failed to destroy matrix data.\n"; status = false; - } else if (A.getRowData(memspace_) != nullptr || - A.getColData(memspace_) != nullptr || - A.getValues(memspace_) != nullptr) { + } else if (A->getRowData(memspace_) != nullptr || + A->getColData(memspace_) != nullptr || + A->getValues(memspace_) != nullptr) { std::cout << "Matrix data pointers are not null after destruction.\n"; status = false; } From 0bc10aa006e6029f9b4bb37a62f7af6caf2dc127 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Tue, 3 Jun 2025 09:36:59 -0400 Subject: [PATCH 09/16] fix asserts for test matrices dimensions --- tests/unit/matrix/SparseTests.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index a72d3fbbf..21e572dfa 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -75,7 +75,7 @@ namespace ReSolve { namespace tests { */ TestOutcome setDataPointers(index_type n, index_type m, index_type nnz) { - assert(nnz % m == 0 && "For this test, nnz must be divisible by m"); + assert(nnz % n == 0 && "For this test, nnz must be divisible by m"); TestStatus status; status = true; @@ -221,6 +221,8 @@ namespace ReSolve { namespace tests { */ TestOutcome copyValuesAndSetDataPointers(index_type n, index_type m, index_type nnz) { + assert(nnz % n == 0 && "For this test, nnz must be divisible by m"); + TestStatus status; status = true; From 10d1094e85747d5c06bc24efe54603890a1f21b4 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Wed, 4 Jun 2025 13:23:25 -0400 Subject: [PATCH 10/16] refactor to take row density as parameter instead of nnz --- tests/unit/matrix/SparseTests.hpp | 132 +++++++++++++++------------ tests/unit/matrix/runSparseTests.cpp | 18 ++-- 2 files changed, 82 insertions(+), 68 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index 21e572dfa..88928ff3a 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -36,7 +36,7 @@ namespace ReSolve { namespace tests { * * @param[in] n - number of rows * @param[in] m - number of columns - * @param[in] nnz - number of non-zeros + * @param[in] row_density - number of non-zeros per row * @param[in] is_symmetric - true if the matrix is symmetric, false otherwise * @param[in] is_expanded - true if the matrix is expanded (all non-zeros are stored explicitly, not assumed based on symmetry), false otherwise @@ -49,17 +49,17 @@ namespace ReSolve { namespace tests { bool is_symmetric = false, bool is_expanded = true) { - TestStatus status; - status = true; + TestStatus success; + success = true; ReSolve::matrix::Csr A(n, m, nnz, is_symmetric, is_expanded); if (A.getNumRows() != n || A.getNumColumns() != m || A.getNnz() != nnz) { std::cout << "Matrix dimensions do not match expected values.\n"; - status = false; + success = false; } - return status.report(__func__); + return success.report(__func__); } /** @@ -68,17 +68,18 @@ namespace ReSolve { namespace tests { * Sets the row, column, and value data pointers for the sparse matrix and * checks if the pointers are set correctly. * - * @param n - number of rows - * @param m - number of columns - * @param nnz - number of non-zeros + * @param[in] n - number of rows + * @param[in] m - number of columns + * @param[in] row_density - number of non-zeros per row + * * @return TestOutcome indicating success or failure of the test */ - TestOutcome setDataPointers(index_type n, index_type m, index_type nnz) + TestOutcome setDataPointers(index_type n, index_type m, index_type row_density) { - assert(nnz % n == 0 && "For this test, nnz must be divisible by m"); - - TestStatus status; - status = true; + TestStatus success; + success = true; + + index_type nnz = n * row_density; // Total non-zeros based on row density ReSolve::matrix::Csr A(n, m, nnz); @@ -97,15 +98,15 @@ namespace ReSolve { namespace tests { if (A.setDataPointers(h_row_data, h_col_data, h_val_data, memory::HOST) != 0) { std::cout << "Failed to set data pointers.\n"; - status = false; + success = false; } else if (A.getRowData(memory::HOST) != h_row_data || A.getColData(memory::HOST) != h_col_data || A.getValues(memory::HOST) != h_val_data) { std::cout << "Data pointers do not point to expected values.\n"; - status = false; + success = false; } - return status.report(__func__); + return success.report(__func__); } /** @@ -116,13 +117,16 @@ namespace ReSolve { namespace tests { * * @param[in] n - number of rows * @param[in] m - number of columns - * @param[in] nnz - number of non-zeros + * @param[in] row_density - number of non-zeros per row + * * @return TestOutcome indicating success or failure of the test */ - TestOutcome setValuesPointer(index_type n, index_type m, index_type nnz) + TestOutcome setValuesPointer(index_type n, index_type m, index_type row_density) { - TestStatus status; - status = true; + TestStatus success; + success = true; + + index_type nnz = n * row_density; // Total non-zeros based on row density ReSolve::matrix::Csr A(n, m, nnz); @@ -133,13 +137,13 @@ namespace ReSolve { namespace tests { if (A.setValuesPointer(val_data, memory::HOST) != 0) { std::cout << "Failed to set values pointer.\n"; - status = false; + success = false; } else if (A.getValues(memory::HOST) != val_data) { std::cout << "Values pointer does not point to expected values.\n"; - status = false; + success = false; } - return status.report(__func__); + return success.report(__func__); } /** @@ -149,15 +153,18 @@ namespace ReSolve { namespace tests { * and verifies the correct unmodified values are stored in the matrix, * and that the values pointer does not point to the original array. * - * @param n - number of rows - * @param m - number of columns - * @param nnz - number of non-zeros + * @param[in] n - number of rows + * @param[in] m - number of columns + * @param[in] row_density - number of non-zeros per row + * * @return TestOutcome indicating success or failure of the test */ - TestOutcome copyValues(index_type n, index_type m, index_type nnz) + TestOutcome copyValues(index_type n, index_type m, index_type row_density) { - TestStatus status; - status = true; + TestStatus success; + success = true; + + index_type nnz = n * row_density; // Total non-zeros based on row density ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); @@ -168,7 +175,7 @@ namespace ReSolve { namespace tests { if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; - status = false; + success = false; } else { // Modify original values to ensure copy worked for (index_type i = 0; i < nnz; ++i) { @@ -177,7 +184,7 @@ namespace ReSolve { namespace tests { if (A->getValues(memspace_) == nullptr) { std::cout << "Values pointer is null after copy.\n"; - status = false; + success = false; } else { real_type* h_val_data; if (memspace_ == memory::HOST) { @@ -190,7 +197,7 @@ namespace ReSolve { namespace tests { for (index_type i = 0; i < nnz; ++i) { if (h_val_data[i] != static_cast(i + 1)) { std::cout << "Copied values do not match expected values.\n"; - status = false; + success = false; break; } } @@ -202,10 +209,10 @@ namespace ReSolve { namespace tests { if (A->destroyMatrixData(memspace_) != 0) { std::cout << "Failed to destroy matrix data.\n"; - status = false; + success = false; } - return status.report(__func__); + return success.report(__func__); } /** @@ -214,17 +221,17 @@ namespace ReSolve { namespace tests { * Copies values into the sparse matrix and then attempts to set the values * pointer, which should fail since the matrix owns the data. * - * @param n - number of rows - * @param m - number of columns - * @param nnz - number of non-zeros + * @param[in] n - number of rows + * @param[in] m - number of columns + * @param[in] row_density - number of non-zeros per row * @return TestOutcome indicating success or failure of the test */ - TestOutcome copyValuesAndSetDataPointers(index_type n, index_type m, index_type nnz) + TestOutcome copyValuesAndSetDataPointers(index_type n, index_type m, index_type row_density) { - assert(nnz % n == 0 && "For this test, nnz must be divisible by m"); + TestStatus success; + success = true; - TestStatus status; - status = true; + index_type nnz = n * row_density; // Total non-zeros based on row density ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); @@ -235,7 +242,7 @@ namespace ReSolve { namespace tests { if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; - status = false; + success = false; } index_type* row_data = new index_type[n + 1]; @@ -249,7 +256,7 @@ namespace ReSolve { namespace tests { if (A->setDataPointers(row_data, col_data, val_data, memspace_) == 0) { std::cout << "Should not have set data pointers after copying values.\n"; - status = false; + success = false; } // Clean up allocated memory @@ -257,7 +264,7 @@ namespace ReSolve { namespace tests { delete[] row_data; delete[] col_data; - return status.report(__func__); + return success.report(__func__); } /** @@ -266,12 +273,17 @@ namespace ReSolve { namespace tests { * Copies a data array using `copyValues`, then attempts to set the values pointer, * and verifies that this results in an error. * + * @param[in] n - number of rows + * @param[in] m - number of columns + * @param[in] row_density - number of non-zeros per row * @return TestOutcome indicating success or failure of the test */ - TestOutcome copyValuesAndSetValues(index_type n, index_type m, index_type nnz) + TestOutcome copyValuesAndSetValues(index_type n, index_type m, index_type row_density) { - TestStatus status; - status = true; + TestStatus success; + success = true; + + index_type nnz = n * row_density; // Total non-zeros based on row density ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); @@ -282,18 +294,18 @@ namespace ReSolve { namespace tests { if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; - status = false; + success = false; } if (A->setValuesPointer(val_data, memspace_) == 0) { std::cout << "Should not have set values pointer when matrix owns data.\n"; - status = false; + success = false; } // Clean up allocated memory delete[] val_data; - return status.report(__func__); + return success.report(__func__); } /** @@ -304,38 +316,40 @@ namespace ReSolve { namespace tests { * * @param[in] n - number of rows * @param[in] m - number of columns - * @param[in] nnz - number of non-zeros + * @param[in] row_density - number of non-zeros per row * * @return TestOutcome indicating success or failure of the test */ - TestOutcome allocateAndDestroyData(index_type n, index_type m, index_type nnz) + TestOutcome allocateAndDestroyData(index_type n, index_type m, index_type row_density) { - TestStatus status; - status = true; + TestStatus success; + success = true; + + index_type nnz = n * row_density; // Total non-zeros based on row density ReSolve::matrix::Csr* A = new ReSolve::matrix::Csr(n, m, nnz); if (A->allocateMatrixData(memspace_) != 0) { std::cout << "Failed to allocate matrix data.\n"; - status = false; + success = false; } else if (A->getRowData(memspace_) == nullptr || A->getColData(memspace_) == nullptr || A->getValues(memspace_) == nullptr) { std::cout << "Matrix data pointers are null after allocation.\n"; - status = false; + success = false; } if (A->destroyMatrixData(memspace_) != 0) { std::cout << "Failed to destroy matrix data.\n"; - status = false; + success = false; } else if (A->getRowData(memspace_) != nullptr || A->getColData(memspace_) != nullptr || A->getValues(memspace_) != nullptr) { std::cout << "Matrix data pointers are not null after destruction.\n"; - status = false; + success = false; } - return status.report(__func__); + return success.report(__func__); } private: diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp index 6a872ad96..ae878741a 100644 --- a/tests/unit/matrix/runSparseTests.cpp +++ b/tests/unit/matrix/runSparseTests.cpp @@ -25,18 +25,18 @@ void runTests(const std::string& backend, ReSolve::tests::TestingResults& result ReSolve::tests::SparseTests test(handler); - result += test.constructor(50, 50, 100); - result += test.constructor(50, 50, 100, true); - result += test.constructor(50, 50, 100, false, false); + result += test.constructor(50, 50, 2); + result += test.constructor(50, 50, 2, true); + result += test.constructor(50, 50, 2, false, false); - result += test.setDataPointers(50, 50, 100); - result += test.setValuesPointer(50, 50, 100); + result += test.setDataPointers(50, 50, 2); + result += test.setValuesPointer(50, 50, 2); - result += test.copyValues(50, 50, 100); - result += test.copyValuesAndSetValues(50, 50, 100); - result += test.copyValuesAndSetDataPointers(50, 50, 100); + result += test.copyValues(50, 50, 2); + result += test.copyValuesAndSetValues(50, 50, 2); + result += test.copyValuesAndSetDataPointers(50, 50, 2); - result += test.allocateAndDestroyData(50, 50, 100); + result += test.allocateAndDestroyData(50, 50, 2); } int main(int, char**) From e4a23e1e244944bc7c4bf54976dfba93d1a7a947 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Wed, 4 Jun 2025 14:08:09 -0400 Subject: [PATCH 11/16] fix for bug on cuda --- tests/unit/matrix/SparseTests.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index 88928ff3a..b9776a5e6 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -190,7 +190,8 @@ namespace ReSolve { namespace tests { if (memspace_ == memory::HOST) { h_val_data = A->getValues(memory::HOST); } else { - mem_.copyArrayDeviceToHost(h_val_data, A->getValues(memory::DEVICE), nnz); + real_type* d_val_data = A->getValues(memory::DEVICE); + mem_.copyArrayDeviceToHost(h_val_data, d_val_data, nnz); } // Check if the copied values are correct From eccce9aec70b6c02f922aa0301bb12a795cb0e11 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Thu, 5 Jun 2025 15:08:30 -0400 Subject: [PATCH 12/16] remove use of matrix handler --- tests/unit/matrix/SparseTests.hpp | 10 ++++------ tests/unit/matrix/runSparseTests.cpp | 4 +--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index b9776a5e6..e6a7af4d7 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -8,20 +8,19 @@ #include #include #include -#include #include namespace ReSolve { namespace tests { class SparseTests : TestBase { public: - SparseTests(ReSolve::MatrixHandler& handler) : handler_(handler) + SparseTests() { - if (handler_.getIsCudaEnabled() || handler_.getIsHipEnabled()) { + #ifdef RESOLVE_USE_GPU memspace_ = memory::DEVICE; - } else { + #else memspace_ = memory::HOST; - } + #endif } ~SparseTests() @@ -354,7 +353,6 @@ namespace ReSolve { namespace tests { } private: - ReSolve::MatrixHandler& handler_; memory::MemorySpace memspace_; MemoryHandler mem_; }; // class SparseTests diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp index ae878741a..625b0de0d 100644 --- a/tests/unit/matrix/runSparseTests.cpp +++ b/tests/unit/matrix/runSparseTests.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include "SparseTests.hpp" @@ -21,9 +20,8 @@ void runTests(const std::string& backend, ReSolve::tests::TestingResults& result WorkspaceType workspace; workspace.initializeHandles(); - ReSolve::MatrixHandler handler(&workspace); - ReSolve::tests::SparseTests test(handler); + ReSolve::tests::SparseTests test; result += test.constructor(50, 50, 2); result += test.constructor(50, 50, 2, true); From 0d3578c1ba36bc0eb9c6fe01f59e761e9379a4d8 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Thu, 5 Jun 2025 15:14:31 -0400 Subject: [PATCH 13/16] pass memspace into constructor --- tests/unit/matrix/SparseTests.hpp | 8 ++------ tests/unit/matrix/runSparseTests.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index e6a7af4d7..b84832f25 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -14,13 +14,9 @@ namespace ReSolve { namespace tests { class SparseTests : TestBase { public: - SparseTests() + SparseTests(memory::MemorySpace memspace = memory::HOST) : memspace_(memspace) { - #ifdef RESOLVE_USE_GPU - memspace_ = memory::DEVICE; - #else - memspace_ = memory::HOST; - #endif + } ~SparseTests() diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp index 625b0de0d..fea2124b1 100644 --- a/tests/unit/matrix/runSparseTests.cpp +++ b/tests/unit/matrix/runSparseTests.cpp @@ -14,14 +14,14 @@ * @param[out] result - test results */ template -void runTests(const std::string& backend, ReSolve::tests::TestingResults& result) +void runTests(const std::string& backend, ReSolve::memory::MemorySpace memspace, ReSolve::tests::TestingResults& result) { - std::cout << "Running tests on " << backend << " device:\n"; + std::cout << "Running tests on " << backend << ":\n"; WorkspaceType workspace; workspace.initializeHandles(); - ReSolve::tests::SparseTests test; + ReSolve::tests::SparseTests test(memspace); result += test.constructor(50, 50, 2); result += test.constructor(50, 50, 2, true); @@ -40,14 +40,14 @@ void runTests(const std::string& backend, ReSolve::tests::TestingResults& result int main(int, char**) { ReSolve::tests::TestingResults result; - runTests("CPU", result); + runTests("CPU", ReSolve::memory::HOST, result); #ifdef RESOLVE_USE_CUDA - runTests("CUDA", result); + runTests("CUDA", ReSolve::memory::DEVICE, result); #endif #ifdef RESOLVE_USE_HIP - runTests("HIP", result); + runTests("HIP", ReSolve::memory::DEVICE, result); #endif return result.summary(); From bc4d3c44b13f2a1b7f5ffc2c2f759e4910e2e035 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Thu, 5 Jun 2025 15:34:51 -0400 Subject: [PATCH 14/16] silence expected errors in copy and set tests --- tests/unit/matrix/runSparseTests.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp index fea2124b1..d3c77ea63 100644 --- a/tests/unit/matrix/runSparseTests.cpp +++ b/tests/unit/matrix/runSparseTests.cpp @@ -23,6 +23,8 @@ void runTests(const std::string& backend, ReSolve::memory::MemorySpace memspace, ReSolve::tests::SparseTests test(memspace); + ReSolve::io::Logger::setVerbosity(ReSolve::io::Logger::NONE); + result += test.constructor(50, 50, 2); result += test.constructor(50, 50, 2, true); result += test.constructor(50, 50, 2, false, false); From 0c49232dd7920bcaccf4d72e136109197c139afe Mon Sep 17 00:00:00 2001 From: shakedregev Date: Thu, 5 Jun 2025 20:28:14 +0000 Subject: [PATCH 15/16] initialized h_val_data --- tests/unit/matrix/SparseTests.hpp | 74 ++++++++++++++++--------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/tests/unit/matrix/SparseTests.hpp b/tests/unit/matrix/SparseTests.hpp index b84832f25..1ba585270 100644 --- a/tests/unit/matrix/SparseTests.hpp +++ b/tests/unit/matrix/SparseTests.hpp @@ -16,7 +16,7 @@ namespace ReSolve { namespace tests { public: SparseTests(memory::MemorySpace memspace = memory::HOST) : memspace_(memspace) { - + } ~SparseTests() @@ -25,24 +25,24 @@ namespace ReSolve { namespace tests { /** * @brief Constructor test for sparse matrix - * + * * Constructs a CSR matrix with the given parameters and confirms that the * parameters are stored correctly. - * + * * @param[in] n - number of rows * @param[in] m - number of columns * @param[in] row_density - number of non-zeros per row * @param[in] is_symmetric - true if the matrix is symmetric, false otherwise - * @param[in] is_expanded - true if the matrix is expanded (all non-zeros + * @param[in] is_expanded - true if the matrix is expanded (all non-zeros are stored explicitly, not assumed based on symmetry), false otherwise - * + * * @return TestOutcome indicating success or failure of the test */ - TestOutcome constructor(index_type n, - index_type m, + TestOutcome constructor(index_type n, + index_type m, index_type nnz, bool is_symmetric = false, - bool is_expanded = true) + bool is_expanded = true) { TestStatus success; success = true; @@ -59,14 +59,14 @@ namespace ReSolve { namespace tests { /** * @brief Test set data pointers for the sparse matrix - * + * * Sets the row, column, and value data pointers for the sparse matrix and * checks if the pointers are set correctly. - * + * * @param[in] n - number of rows * @param[in] m - number of columns * @param[in] row_density - number of non-zeros per row - * + * * @return TestOutcome indicating success or failure of the test */ TestOutcome setDataPointers(index_type n, index_type m, index_type row_density) @@ -94,8 +94,8 @@ namespace ReSolve { namespace tests { if (A.setDataPointers(h_row_data, h_col_data, h_val_data, memory::HOST) != 0) { std::cout << "Failed to set data pointers.\n"; success = false; - } else if (A.getRowData(memory::HOST) != h_row_data || - A.getColData(memory::HOST) != h_col_data || + } else if (A.getRowData(memory::HOST) != h_row_data || + A.getColData(memory::HOST) != h_col_data || A.getValues(memory::HOST) != h_val_data) { std::cout << "Data pointers do not point to expected values.\n"; success = false; @@ -106,14 +106,14 @@ namespace ReSolve { namespace tests { /** * @brief Test setting values pointer for the sparse matrix - * + * * Sets the values pointer for the sparse matrix and checks if the pointer * points to the expected values. - * + * * @param[in] n - number of rows * @param[in] m - number of columns * @param[in] row_density - number of non-zeros per row - * + * * @return TestOutcome indicating success or failure of the test */ TestOutcome setValuesPointer(index_type n, index_type m, index_type row_density) @@ -143,15 +143,15 @@ namespace ReSolve { namespace tests { /** * @brief Test copying values into the sparse matrix - * + * * Copies values into the sparse matrix, modifies the original values, - * and verifies the correct unmodified values are stored in the matrix, + * and verifies the correct unmodified values are stored in the matrix, * and that the values pointer does not point to the original array. - * + * * @param[in] n - number of rows * @param[in] m - number of columns * @param[in] row_density - number of non-zeros per row - * + * * @return TestOutcome indicating success or failure of the test */ TestOutcome copyValues(index_type n, index_type m, index_type row_density) @@ -167,7 +167,7 @@ namespace ReSolve { namespace tests { for (index_type i = 0; i < nnz; ++i) { val_data[i] = static_cast(i + 1); } - + real_type* h_val_data = nullptr; if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; success = false; @@ -181,12 +181,16 @@ namespace ReSolve { namespace tests { std::cout << "Values pointer is null after copy.\n"; success = false; } else { - real_type* h_val_data; if (memspace_ == memory::HOST) { h_val_data = A->getValues(memory::HOST); } else { real_type* d_val_data = A->getValues(memory::DEVICE); + h_val_data = new real_type[nnz]; mem_.copyArrayDeviceToHost(h_val_data, d_val_data, nnz); + if (h_val_data == nullptr) { + std::cout << "Failed to copy values from device to host.\n"; + success = false; + } } // Check if the copied values are correct @@ -213,10 +217,10 @@ namespace ReSolve { namespace tests { /** * @brief Verify that matrix will not reset data pointers when it currently owns data. - * + * * Copies values into the sparse matrix and then attempts to set the values * pointer, which should fail since the matrix owns the data. - * + * * @param[in] n - number of rows * @param[in] m - number of columns * @param[in] row_density - number of non-zeros per row @@ -239,7 +243,7 @@ namespace ReSolve { namespace tests { if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; success = false; - } + } index_type* row_data = new index_type[n + 1]; for (index_type i = 0; i <= n; ++i) { @@ -261,12 +265,12 @@ namespace ReSolve { namespace tests { delete[] col_data; return success.report(__func__); - } + } /** * @brief Verify that matrix will not reset values pointer when it currently owns data. * - * Copies a data array using `copyValues`, then attempts to set the values pointer, + * Copies a data array using `copyValues`, then attempts to set the values pointer, * and verifies that this results in an error. * * @param[in] n - number of rows @@ -291,7 +295,7 @@ namespace ReSolve { namespace tests { if (A->copyValues(val_data, memory::HOST, memspace_) != 0) { std::cout << "Failed to copy values.\n"; success = false; - } + } if (A->setValuesPointer(val_data, memspace_) == 0) { std::cout << "Should not have set values pointer when matrix owns data.\n"; @@ -306,14 +310,14 @@ namespace ReSolve { namespace tests { /** * @brief Test allocating and destroying matrix data - * + * * Allocates memory for the sparse matrix data and checks if the pointers * are not null after allocation. Then destroys the allocated data. - * + * * @param[in] n - number of rows * @param[in] m - number of columns * @param[in] row_density - number of non-zeros per row - * + * * @return TestOutcome indicating success or failure of the test */ TestOutcome allocateAndDestroyData(index_type n, index_type m, index_type row_density) @@ -328,8 +332,8 @@ namespace ReSolve { namespace tests { if (A->allocateMatrixData(memspace_) != 0) { std::cout << "Failed to allocate matrix data.\n"; success = false; - } else if (A->getRowData(memspace_) == nullptr || - A->getColData(memspace_) == nullptr || + } else if (A->getRowData(memspace_) == nullptr || + A->getColData(memspace_) == nullptr || A->getValues(memspace_) == nullptr) { std::cout << "Matrix data pointers are null after allocation.\n"; success = false; @@ -338,8 +342,8 @@ namespace ReSolve { namespace tests { if (A->destroyMatrixData(memspace_) != 0) { std::cout << "Failed to destroy matrix data.\n"; success = false; - } else if (A->getRowData(memspace_) != nullptr || - A->getColData(memspace_) != nullptr || + } else if (A->getRowData(memspace_) != nullptr || + A->getColData(memspace_) != nullptr || A->getValues(memspace_) != nullptr) { std::cout << "Matrix data pointers are not null after destruction.\n"; success = false; From b302809e1d2c7c3949b64e3034426c5fefcdede1 Mon Sep 17 00:00:00 2001 From: Adham Ibrahim Date: Thu, 5 Jun 2025 16:37:48 -0400 Subject: [PATCH 16/16] add rectangular matrix tests --- tests/unit/matrix/runSparseTests.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/unit/matrix/runSparseTests.cpp b/tests/unit/matrix/runSparseTests.cpp index d3c77ea63..ffa839f00 100644 --- a/tests/unit/matrix/runSparseTests.cpp +++ b/tests/unit/matrix/runSparseTests.cpp @@ -26,17 +26,24 @@ void runTests(const std::string& backend, ReSolve::memory::MemorySpace memspace, ReSolve::io::Logger::setVerbosity(ReSolve::io::Logger::NONE); result += test.constructor(50, 50, 2); + result += test.constructor(50, 100, 2); result += test.constructor(50, 50, 2, true); result += test.constructor(50, 50, 2, false, false); result += test.setDataPointers(50, 50, 2); + result += test.setDataPointers(50, 100, 2); result += test.setValuesPointer(50, 50, 2); + result += test.setValuesPointer(50, 100, 2); result += test.copyValues(50, 50, 2); + result += test.copyValues(50, 100, 2); result += test.copyValuesAndSetValues(50, 50, 2); + result += test.copyValuesAndSetValues(50, 100, 2); result += test.copyValuesAndSetDataPointers(50, 50, 2); + result += test.copyValuesAndSetDataPointers(50, 100, 2); result += test.allocateAndDestroyData(50, 50, 2); + result += test.allocateAndDestroyData(50, 100, 2); } int main(int, char**)