diff --git a/CMakeLists.txt b/CMakeLists.txt index 91d6b4d11..0384c46e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -378,9 +378,9 @@ if (HIOP_WITH_MAKETEST) if(HIOP_USE_MPI) add_test(NAME VectorTest_mpi COMMAND ${MPICMD} -n 2 "$") endif(HIOP_USE_MPI) - add_test(NAME MatrixTest COMMAND ${RUNCMD} "$") + add_test(NAME MatrixTest COMMAND ${RUNCMD} "$") if(HIOP_USE_MPI) - add_test(NAME MatrixTest_mpi COMMAND ${MPICMD} -n 2 "$") + add_test(NAME MatrixTest_mpi COMMAND ${MPICMD} -n 2 "$") endif(HIOP_USE_MPI) add_test(NAME SparseMatrixTest COMMAND ${RUNCMD} "$") add_test(NAME SymmetricSparseMatrixTest COMMAND ${RUNCMD} "$") diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 170bb0a18..e83bd90e5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -2,7 +2,7 @@ set(testVector_SRC testVector.cpp LinAlg/vectorTestsPar.cpp LinAlg/vectorTestsIntSeq.cpp) # Set sources for dense matrix tests -set(testMatrix_SRC testMatrix.cpp LinAlg/matrixTestsDense.cpp) +set(testMatrix_SRC testMatrixDense.cpp LinAlg/matrixTestsDenseRowMajor.cpp) # Set sources for sparse matrix tests set(testMatrixSparse_SRC testMatrixSparse.cpp LinAlg/matrixTestsSparseTriplet.cpp) @@ -21,7 +21,7 @@ endif() if(HIOP_USE_GPU) set_source_files_properties(testVector.cpp LinAlg/vectorTestsRajaPar.cpp PROPERTIES LANGUAGE CUDA) set_source_files_properties(testVector.cpp LinAlg/vectorTestsIntRaja.cpp PROPERTIES LANGUAGE CUDA) - set_source_files_properties(testMatrix.cpp LinAlg/matrixTestsRajaDense.cpp PROPERTIES LANGUAGE CUDA) + set_source_files_properties(testMatrixDense.cpp LinAlg/matrixTestsRajaDense.cpp PROPERTIES LANGUAGE CUDA) set_source_files_properties(testMatrixSparse.cpp LinAlg/matrixTestsRajaSparseTriplet.cpp PROPERTIES LANGUAGE CUDA) set_source_files_properties(testMatrixSymSparse.cpp LinAlg/matrixTestsRajaSymSparseTriplet.cpp PROPERTIES LANGUAGE CUDA) endif() @@ -31,8 +31,8 @@ add_executable(testVector ${testVector_SRC}) target_link_libraries(testVector PRIVATE hiop) # Build matrix test -add_executable(testMatrix ${testMatrix_SRC}) -target_link_libraries(testMatrix PRIVATE hiop) +add_executable(testMatrixDense ${testMatrix_SRC}) +target_link_libraries(testMatrixDense PRIVATE hiop) # Build sparse matrix test add_executable(testMatrixSparse ${testMatrixSparse_SRC}) @@ -44,7 +44,7 @@ target_link_libraries(testMatrixSymSparse PRIVATE hiop) if(HIOP_USE_RAJA) target_link_libraries(testVector PRIVATE umpire RAJA OpenMP::OpenMP_CXX) - target_link_libraries(testMatrix PRIVATE umpire RAJA OpenMP::OpenMP_CXX) + target_link_libraries(testMatrixDense PRIVATE umpire RAJA OpenMP::OpenMP_CXX) target_link_libraries(testMatrixSparse PRIVATE umpire RAJA OpenMP::OpenMP_CXX) target_link_libraries(testMatrixSymSparse PRIVATE umpire RAJA OpenMP::OpenMP_CXX) endif() diff --git a/tests/LinAlg/matrixTests.hpp b/tests/LinAlg/matrixTests.hpp deleted file mode 100644 index 6ed85b757..000000000 --- a/tests/LinAlg/matrixTests.hpp +++ /dev/null @@ -1,1149 +0,0 @@ -// Copyright (c) 2017, Lawrence Livermore National Security, LLC. -// Produced at the Lawrence Livermore National Laboratory (LLNL). -// Written by Cosmin G. Petra, petra1@llnl.gov. -// LLNL-CODE-742473. All rights reserved. -// -// This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp -// is released under the BSD 3-clause license (https://opensource.org/licenses/BSD-3-Clause). -// Please also read “Additional BSD Notice” below. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// i. Redistributions of source code must retain the above copyright notice, this list -// of conditions and the disclaimer below. -// ii. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the documentation and/or -// other materials provided with the distribution. -// iii. Neither the name of the LLNS/LLNL nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -// SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Additional BSD Notice -// 1. This notice is required to be provided under our contract with the U.S. Department -// of Energy (DOE). This work was produced at Lawrence Livermore National Laboratory under -// Contract No. DE-AC52-07NA27344 with the DOE. -// 2. Neither the United States Government nor Lawrence Livermore National Security, LLC -// nor any of their employees, makes any warranty, express or implied, or assumes any -// liability or responsibility for the accuracy, completeness, or usefulness of any -// information, apparatus, product, or process disclosed, or represents that its use would -// not infringe privately-owned rights. -// 3. Also, reference herein to any specific commercial products, process, or services by -// trade name, trademark, manufacturer or otherwise does not necessarily constitute or -// imply its endorsement, recommendation, or favoring by the United States Government or -// Lawrence Livermore National Security, LLC. The views and opinions of authors expressed -// herein do not necessarily state or reflect those of the United States Government or -// Lawrence Livermore National Security, LLC, and shall not be used for advertising or -// product endorsement purposes. - -/** - * @file matrixTests.hpp - * - * @author Asher Mancinelli , PNNL - * @author Jake Ryan , PNNL - * @author Robert Rutherford , PNNL - * @author Slaven Peles , PNNL - * - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include "testBase.hpp" - -namespace hiop { namespace tests { - -class MatrixTests : public TestBase -{ -public: - MatrixTests() {} - virtual ~MatrixTests(){} - - int matrixSetToZero(hiop::hiopMatrixDense& A, const int rank) - { - A.setToConstant(one); - A.setToZero(); - const int fail = verifyAnswer(&A, zero); - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - int matrixSetToConstant(hiop::hiopMatrixDense& A, const int rank) - { - A.setToConstant(one); - int fail = verifyAnswer(&A, one); - A.setToConstant(two); - fail += verifyAnswer(&A, two); - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - int matrixCopyFrom( - hiopMatrixDense &dst, - hiopMatrixDense &src, - const int rank) - { - assert(dst.n() == src.n() && "Did you pass in matrices of the same size?"); - assert(dst.m() == src.m() && "Did you pass in matrices of the same size?"); - assert(getNumLocRows(&dst) == getNumLocRows(&src) && "Did you pass in matrices of the same size?"); - assert(getNumLocCols(&dst) == getNumLocCols(&src) && "Did you pass in matrices of the same size?"); - const real_type src_val = one; - - // Test copying src another matrix - src.setToConstant(src_val); - dst.setToZero(); - - dst.copyFrom(src); - int fail = verifyAnswer(&dst, src_val); - - // test copying src a raw buffer - const size_t buf_len = getNumLocRows(&src) * getNumLocCols(&src); - real_type *src_buf = getLocalData(&src); - dst.setToZero(); - - dst.copyFrom(src_buf); - fail += verifyAnswer(&dst, src_val); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &dst); - } - - /* - * y_{glob} \leftarrow \beta y_{glob} + \alpha A_{glob \times loc} x_{loc} - */ - int matrixTimesVec( - hiop::hiopMatrixDense& A, - hiop::hiopVector& y, - hiop::hiopVector& x, - const int rank=0) - { - const global_ordinal_type N_glob = A.n(); - assert(getLocalSize(&y) == getNumLocRows(&A) && "Did you pass in vectors of the correct sizes?"); - assert(getLocalSize(&x) == getNumLocCols(&A) && "Did you pass in vectors of the correct sizes?"); - const real_type alpha = one, - beta = one, - A_val = one, - y_val = three, - x_val = three; - int fail = 0; - - y.setToConstant(y_val); - x.setToConstant(x_val); - A.setToConstant(A_val); - - A.timesVec(beta, y, alpha, x); - - real_type expected = (beta * y_val) + (alpha * A_val * x_val * N_glob); - fail += verifyAnswer(&y, expected); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /* - * y = beta * y + alpha * A^T * x - * - * Notice that since A^T, x must not be distributed in this case, whereas - * the plain `timesVec' nessecitated that x be distributed and y not be. - */ - int matrixTransTimesVec( - hiop::hiopMatrixDense& A, - hiop::hiopVector& x, - hiop::hiopVector& y, - const int rank=0) - { - const local_ordinal_type M = getNumLocRows(&A); - const local_ordinal_type N = getNumLocCols(&A); - - // Take m() because A will be transposed - const global_ordinal_type N_glob = A.m(); - assert(getLocalSize(&x) == getNumLocRows(&A) && "Did you pass in vectors of the correct sizes?"); - assert(getLocalSize(&y) == getNumLocCols(&A) && "Did you pass in vectors of the correct sizes?"); - const real_type alpha = one, - beta = one, - A_val = one, - y_val = three, - x_val = three; - int fail = 0; - - // Index of row of A that will be set to zero, - // and index of y that will be beta * y_val - const local_ordinal_type index_to_zero = N-1; - - A.setToConstant(A_val); - y.setToConstant(y_val); - x.setToConstant(x_val); - - /* - * Zero a row of A^T to test that the resulting vector - * has its initial value as the first element, ensuring that - * the matrix is correctly transposed. - */ - for (int i=0; i real_type - { - const bool isZerodRow = (i == index_to_zero); - return isZerodRow ? - beta * y_val : - (beta * y_val) + (alpha * A_val * x_val * N_glob); - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /** - * W = beta * W + alpha * A * M - * - * Shapes: - * A: KxM - * M: MxN - * W: KxN - * all local - */ - int matrixTimesMat( - hiop::hiopMatrixDense& A, - hiop::hiopMatrixDense& X, - hiop::hiopMatrixDense& W, - const int rank=0) - { - const local_ordinal_type K = getNumLocCols(&A); - assert(K == A.n()); - assert(getNumLocCols(&X) == X.n()); - assert(K == getNumLocRows(&X)); - assert(getNumLocRows(&A) == getNumLocRows(&W)); - assert(getNumLocCols(&X) == getNumLocCols(&W)); - const real_type A_val = two, - X_val = three, - W_val = two, - alpha = two, - beta = two; - - A.setToConstant(A_val); - W.setToConstant(W_val); - X.setToConstant(X_val); - A.timesMat(beta, W, alpha, X); - real_type expected = (beta * W_val) + (alpha * A_val * X_val * K); - - const int fail = verifyAnswer(&W, expected); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /* - * W = beta * W + alpha * this^T * X - * - * A: kxm local - * W: mxn - * X: kxn - * - */ - int matrixTransTimesMat( - hiop::hiopMatrixDense& A_local, - hiop::hiopMatrixDense& W, - hiop::hiopMatrixDense& X, - const int rank) - { - const local_ordinal_type K = getNumLocRows(&A_local); - const global_ordinal_type N_loc = getNumLocCols(&X); - assert(getNumLocCols(&A_local) == getNumLocRows(&W) && "Matrices have mismatched shapes"); - assert(X.n() == W.n() && "Matrices have mismatched shapes"); - assert(N_loc == getNumLocCols(&W) && "Matrices have mismatched shapes"); - assert(K == getNumLocRows(&X) && "Matrices have mismatched shapes"); - const real_type A_val = two, - X_val = three, - W_val = two, - alpha = two, - beta = two; - - /* - * One row of X will be set to zero to ensure - * the matrix multiply and transpose operations are - * working correctly. - */ - const int idx_of_zero_row = K - 1; - - A_local.setToConstant(A_val); - W.setToConstant(W_val); - X.setToConstant(X_val); - - // X[idx][:] = 0 - for (int i=0; i real_type - { - return j == idx_of_zero_col ? (beta * W_val) : (beta * W_val) + (alpha * A_val * X_val * Nglob); - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /* - * this += alpha * diag - */ - int matrixAddDiagonal( - hiop::hiopMatrixDense& A, - hiop::hiopVector& x, - const int rank=0) - { - int fail = 0; - assert(getNumLocCols(&A) == getLocalSize(&x)); - assert(getNumLocRows(&A) == getLocalSize(&x)); - assert(getNumLocRows(&A) == A.n()); - assert(A.n() == x.get_size()); - assert(A.m() == x.get_size()); - static const real_type alpha = two, - A_val = quarter, - x_val = half; - - A.setToConstant(A_val); - x.setToConstant(x_val); - A.addDiagonal(alpha, x); - fail += verifyAnswer(&A, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - const bool isOnDiagonal = (i == j); - return isOnDiagonal ? A_val + x_val * alpha : A_val; - }); - - A.setToConstant(A_val); - A.addDiagonal(alpha); - fail += verifyAnswer(&A, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - const bool isOnDiagonal = (i == j); - return isOnDiagonal ? A_val + alpha : A_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /** - * @breif this += alpha * subdiag - * - * @note this test checks all three overloads: - * - addSubDiagonal(const double&, long long, const hiopVector&) - * - addSubDiagonal(int, const double&, const hiopVector&, int, int) - * - addSubDiagonal(int, int, const double&) - */ - int matrixAddSubDiagonal( - hiop::hiopMatrixDense& A, - hiop::hiopVector& x, - const int rank=0) - { - int fail = 0; - const local_ordinal_type N = getNumLocCols(&A); - const local_ordinal_type x_len = getLocalSize(&x); - const real_type alpha = half; - const real_type A_val = half; - const real_type x_val = one; - assert(N == A.n() && "Test should only be ran sequentially."); - assert(N == A.m() && "Test should only run with symmetric matrices."); - - // Test the overload that assumes the entire source vector - // will be added to the subdiagonal - local_ordinal_type start_idx = N - x_len; - - A.setToConstant(A_val); - x.setToConstant(x_val); - A.addSubDiagonal(alpha, start_idx, x); - fail += verifyAnswer(&A, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - const bool isOnSubDiagonal = (i>=start_idx && i==j); - return isOnSubDiagonal ? A_val + x_val * alpha : A_val; - }); - - // We're only going to add n-1 elements of the vector - // Test the overload that specifies subset of the vector - // to be added to subdiagonal - local_ordinal_type start_idx_src = 1; - local_ordinal_type num_elements_to_add = x_len - start_idx_src; - local_ordinal_type start_idx_dest = (N - x_len) + start_idx_src; - - A.setToConstant(A_val); - x.setToConstant(x_val); - A.addSubDiagonal(start_idx_dest, alpha, x, start_idx_src, num_elements_to_add); - - fail += verifyAnswer(&A, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - const bool isOnSubDiagonal = (i>=start_idx_dest && i==j); - return isOnSubDiagonal ? A_val + x_val * alpha : A_val; - }); - - // Operating on N-2 elements s.t. the first and last elements of the sub - // diagonal are not operated on. - start_idx_dest = 1; - const double c = two; - const int num_elems = N - 2; - A.setToConstant(A_val); - A.addSubDiagonal(start_idx_dest, num_elems, c); - fail += verifyAnswer(&A, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - const bool isOperatedOn = i >= start_idx_dest && - i == j && - i < start_idx_dest + num_elems; - return isOperatedOn ? A_val + c : A_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /* - * A += alpha * B - */ - int matrixAddMatrix( - hiop::hiopMatrixDense& A, - hiop::hiopMatrixDense& B, - const int rank) - { - assert(getNumLocRows(&A) == getNumLocRows(&B)); - assert(getNumLocCols(&A) == getNumLocCols(&B)); - const real_type alpha = half, - A_val = half, - B_val = one; - - A.setToConstant(A_val); - B.setToConstant(B_val); - A.addMatrix(alpha, B); - const int fail = verifyAnswer(&A, A_val + B_val * alpha); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /* - * Block of W += alpha*A - * - * Precondition: W is square - */ - // int matrixAddToSymDenseMatrixUpperTriangle( - // hiop::hiopMatrixDense& _W, - // hiop::hiopMatrixDense& A, - // const int rank=0) - // { - // // This method only takes hiopMatrixDense - // auto W = dynamic_cast(&_W); - // const local_ordinal_type N_loc = getNumLocCols(W); - // const local_ordinal_type A_M = getNumLocRows(&A); - // const local_ordinal_type A_N_loc = getNumLocCols(&A); - // assert(W->m() == W->n()); - // assert(getNumLocRows(W) >= getNumLocRows(&A)); - // assert(W->n() >= A.n()); - - // const local_ordinal_type start_idx_row = 0; - // const local_ordinal_type start_idx_col = N_loc - A_N_loc; - // const real_type alpha = half, - // A_val = half, - // W_val = one; - // int fail = 0; - - // // Check with non-1 alpha - // A.setToConstant(A_val); - // W->setToConstant(W_val); - // A.addToSymDenseMatrixUpperTriangle(start_idx_row, start_idx_col, alpha, *W); - // fail += verifyAnswer(W, - // [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - // { - // const bool isUpperTriangle = ( - // i>=start_idx_row && i=start_idx_col && j(&_W); - const local_ordinal_type N_loc = getNumLocCols(W); - const local_ordinal_type A_M = getNumLocRows(&A); - const local_ordinal_type A_N_loc = getNumLocCols(&A); - assert(W->m() == W->n()); - assert(getNumLocRows(W) >= getNumLocRows(&A)); - assert(W->n() >= A.n()); - - const local_ordinal_type start_idx_row = 0; - const local_ordinal_type start_idx_col = N_loc - A_M; - const real_type alpha = half, - A_val = half, - W_val = one; - - A.setToConstant(A_val); - W->setToConstant(W_val); - A.transAddToSymDenseMatrixUpperTriangle(start_idx_row, start_idx_col, alpha, *W); - const int fail = verifyAnswer(W, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - const bool isTransUpperTriangle = ( - i>=start_idx_row && i=start_idx_col && j= A.n()); - assert(getNumLocCols(&A) <= getNumLocCols(&W)); - //auto W = dynamic_cast(&_W); - // Map the upper triangle of A to W starting - // at W's upper left corner - const local_ordinal_type diag_start = 0; - int fail = 0; - const real_type alpha = half, - A_val = half, - W_val = one; - - A.setToConstant(A_val); - W.setToConstant(W_val); - A.addUpperTriangleToSymDenseMatrixUpperTriangle(diag_start, alpha, W); - fail += verifyAnswer(&W, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - bool isUpperTriangle = (i>=diag_start && i=i && j real_type - { - (void)j; // j is unused - const bool isLastRow = (i == init_num_rows); - return isLastRow ? vec_val : A_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - /** - * Tests function that copies rows from source to destination starting from - * `dst_start_idx` in the same order. - * - */ - int matrixCopyRowsFrom( - hiopMatrixDense &dst, - hiopMatrixDense &src, - const int rank) - { - assert(dst.n() == src.n()); - assert(dst.m() > src.m()); - assert(getNumLocCols(&dst) == getNumLocCols(&src)); - assert(getNumLocRows(&dst) > getNumLocRows(&src)); - const real_type dst_val = one; - const real_type src_val = two; - const local_ordinal_type dst_start_idx = dst.m() - src.m(); - local_ordinal_type num_rows_to_copy = src.m(); - const local_ordinal_type src_num_rows = src.m(); - - // Test copying continuous rows from matrix - dst.setToConstant(dst_val); - src.setToConstant(src_val); - - dst.copyRowsFrom(src, num_rows_to_copy, dst_start_idx); - - int fail = verifyAnswer(&dst, - [=](local_ordinal_type i, local_ordinal_type j) -> real_type - { - (void)j; // j is unused - const bool isRowCopiedOver = ( - i >= dst_start_idx && - i < dst_start_idx + src_num_rows); - return isRowCopiedOver ? src_val : dst_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &dst); - } - - /** - * Tests function that copies rows from source to destination in order - * specified by index array `row_idxs`. - * - */ - int matrixCopyRowsFromSelect( - hiopMatrixDense &dst, - hiopMatrixDense &src, - const int rank) - { - assert(dst.n() == src.n()); - assert(getNumLocCols(&dst) == getNumLocCols(&src)); - const real_type dst_val = one; - const real_type src_val = two; - const local_ordinal_type num_rows_to_copy = dst.m(); - assert(num_rows_to_copy <= src.m()); - - // Test copying continuous rows from matrix - dst.setToConstant(dst_val); - src.setToConstant(src_val); - global_ordinal_type *row_idxs = new global_ordinal_type[num_rows_to_copy]; - for (global_ordinal_type i = 0; i < num_rows_to_copy; ++i) - row_idxs[i] = i; - row_idxs[0] = num_rows_to_copy - 1; - row_idxs[num_rows_to_copy - 1] = 0; - setLocalRow(&src, num_rows_to_copy - 1, zero); - - dst.copyRowsFrom(src, row_idxs, num_rows_to_copy); - - int fail = verifyAnswer(&dst, - [=](local_ordinal_type i, local_ordinal_type j) -> real_type - { - (void)j; // j is unused - return i == 0 ? zero : src_val; - }); - - delete [] row_idxs; - printMessage(fail, __func__, rank); - return reduceReturn(fail, &dst); - } - - int matrixCopyBlockFromMatrix( - hiopMatrixDense &src, - hiopMatrixDense &dst, - const int rank=0) - { - assert(src.n() < dst.n() - && "Src mat must be smaller than dst mat"); - assert(src.m() < dst.m() - && "Src mat must be smaller than dst mat"); - assert(getNumLocCols(&src) < getNumLocCols(&dst) - && "Src mat must be smaller than dst mat"); - const real_type src_val = one; - const real_type dst_val = two; - - // Copy matrix block into downmost and rightmost location - // possible - const local_ordinal_type src_num_rows = getNumLocRows(&src); - const local_ordinal_type src_num_cols = getNumLocCols(&src); - const local_ordinal_type dst_start_row = getNumLocRows(&dst) - src_num_rows; - const local_ordinal_type dst_start_col = getNumLocCols(&dst) - src_num_cols; - - src.setToConstant(src_val); - dst.setToConstant(dst_val); - dst.copyBlockFromMatrix(dst_start_row, dst_start_col, src); - - const int fail = verifyAnswer(&dst, - [=](local_ordinal_type i, local_ordinal_type j) -> real_type - { - const bool isIdxCopiedFromSource = ( - i >= dst_start_row && i < dst_start_row + src_num_rows && - j >= dst_start_col && j < dst_start_col + src_num_cols); - return isIdxCopiedFromSource ? src_val : dst_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &dst); - } - - int matrixCopyFromMatrixBlock( - hiopMatrixDense &src, - hiopMatrixDense &dst, - const int rank=0) - { - assert(src.n() > dst.n() - && "Src mat must be larger than dst mat"); - assert(src.m() > dst.m() - && "Src mat must be larger than dst mat"); - assert(getNumLocCols(&src) > getNumLocCols(&dst) - && "Src mat must be larger than dst mat"); - const local_ordinal_type dst_m = getNumLocRows(&dst); - const local_ordinal_type dst_n = getNumLocCols(&dst); - const local_ordinal_type src_m = getNumLocRows(&src); - const local_ordinal_type src_n = getNumLocCols(&src); - const local_ordinal_type block_start_row = (src_m - getNumLocRows(&dst)) - 1; - const local_ordinal_type block_start_col = (src_n - getNumLocCols(&dst)) - 1; - - const real_type src_val = one; - const real_type dst_val = two; - src.setToConstant(src_val); - if (rank == 0) - setLocalElement(&src, src_m - 1, src_n - 1, zero); - dst.setToConstant(dst_val); - - dst.copyFromMatrixBlock(src, block_start_row, block_start_col); - - const int fail = verifyAnswer(&dst, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - // This is the element set to zero in src - // before being copied over - if (i == dst_m && j == dst_n && rank == 0) - return zero; - else - return src_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &dst); - } - - /** - * shiftRows does not overwrite rows in the opposite direction - * they are shifted. For example - * @verbatim - * 2 2 2 2 2 2 - * 1 1 1 1 1 1 - * 1 1 1 shiftRows(2) -> 2 2 2 - * @endverbatim - * The uppermost row is not overwritten by the 1-row that would - * wrap around and replace it. - */ - int matrixShiftRows( - hiopMatrixDense &A, - const int rank) - { - const local_ordinal_type M = getNumLocRows(&A); - local_ordinal_type uniq_row_idx = 0; - local_ordinal_type shift = M - 1; - int fail = 0; - - const real_type A_val = one; - const real_type uniq_row_val = two; - A.setToConstant(A_val); - - // Set one row to a unique value - setLocalRow(&A, uniq_row_idx, uniq_row_val); - A.shiftRows(shift); - - fail += verifyAnswer(&A, - [=](local_ordinal_type i, local_ordinal_type j) -> real_type - { - (void)j; // j is unused - const bool isUniqueRow = ( - i == (uniq_row_idx + shift) || - i == uniq_row_idx); - return isUniqueRow ? uniq_row_val : A_val; - }); - - // Now check negative shift - shift *= -1; - uniq_row_idx = M - 1; - A.setToConstant(A_val); - setLocalRow(&A, uniq_row_idx, uniq_row_val); - A.shiftRows(shift); - - fail += verifyAnswer(&A, - [=] (local_ordinal_type i, local_ordinal_type j) -> real_type - { - (void)j; // j is unused - const bool isUniqueRow = ( - i == (uniq_row_idx + shift) || - i == uniq_row_idx); - return isUniqueRow ? uniq_row_val : A_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - int matrixReplaceRow( - hiopMatrixDense &A, - hiopVector &vec, - const int rank) - { - const local_ordinal_type M = getNumLocRows(&A); - assert(getNumLocCols(&A) == vec.get_local_size() && "Did you pass a vector and matrix of compatible lengths?"); - assert(A.n() == vec.get_size() && "Did you pass a vector and matrix of compatible lengths?"); - - const local_ordinal_type row_idx = M - 1; - const local_ordinal_type col_idx = 1; - const real_type A_val = one; - const real_type vec_val = two; - A.setToConstant(A_val); - vec.setToConstant(vec_val); - setLocalElement(&vec, col_idx, zero); - - A.replaceRow(row_idx, vec); - const int fail = verifyAnswer(&A, - [=](local_ordinal_type i, local_ordinal_type j) -> real_type - { - // Was the row replaced? - if (i == row_idx) - { - // Was the value at col_idx set to zero? - if (j == col_idx) - return zero; - else - return vec_val; - } - // The matrix should be otherwise unchanged. - else - { - return A_val; - } - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - - int matrixGetRow( - hiopMatrixDense &A, - hiopVector &vec, - const int rank) - { - const local_ordinal_type N = getNumLocCols(&A); - const local_ordinal_type M = getNumLocRows(&A); - assert(N == vec.get_local_size() && "Did you pass a vector and matrix of compatible lengths?"); - assert(A.n() == vec.get_size() && "Did you pass a vector and matrix of compatible lengths?"); - - // Set one value in the matrix row to be retrieved to be a unique value - const local_ordinal_type row_idx = M - 1; - const local_ordinal_type col_idx = N - 1; - const real_type A_val = one; - const real_type vec_val = two; - A.setToConstant(A_val); - if (rank == 0) - setLocalElement(&A, row_idx, col_idx, zero); - vec.setToConstant(vec_val); - A.getRow(row_idx, vec); - - const int fail = verifyAnswer(&vec, - [=](local_ordinal_type i) -> real_type - { - if (rank == 0 && i == col_idx) - return zero; - else - return A_val; - }); - - printMessage(fail, __func__, rank); - return reduceReturn(fail, &A); - } - -#ifdef HIOP_DEEPCHECKS - int matrixAssertSymmetry( - hiop::hiopMatrixDense& A, - const int rank=0) - { - const local_ordinal_type M = getNumLocRows(&A); - const local_ordinal_type N = getNumLocCols(&A); - int fail = 0; - - assert(A.m() == A.n()); - A.setToConstant(one); - fail += !A.assertSymmetry(eps); - - // Set first row and column to zero globally - for (int i=0; i expect) = 0; - virtual int verifyAnswer(hiop::hiopVector* x, real_type answer) = 0; - virtual int verifyAnswer( - hiop::hiopVector* x, - std::function expect) = 0; - virtual bool reduceReturn(int failures, hiop::hiopMatrixDense* A) = 0; - /* - * Returns true and sets local coordinate pair if global indices - * maps to local indices, otherwise false and does not alter - * local coordinates. - */ - virtual bool globalToLocalMap( - hiop::hiopMatrixDense* A, - const global_ordinal_type row, - const global_ordinal_type col, - local_ordinal_type& local_row, - local_ordinal_type& local_col) = 0; -}; - -}} // namespace hiop{ namespace tests{ diff --git a/tests/LinAlg/matrixTestsDense.hpp b/tests/LinAlg/matrixTestsDense.hpp index 2fe772131..00be67714 100644 --- a/tests/LinAlg/matrixTestsDense.hpp +++ b/tests/LinAlg/matrixTestsDense.hpp @@ -50,62 +50,1065 @@ * @file matrixTestsDense.hpp * * @author Asher Mancinelli , PNNL + * @author Jake Ryan , PNNL + * @author Robert Rutherford , PNNL * @author Slaven Peles , PNNL * */ - #pragma once -#include "matrixTests.hpp" -#include "hiopVectorPar.hpp" +#include +#include +#include +#include +#include +#include +#include "testBase.hpp" namespace hiop { namespace tests { -class MatrixTestsDense : public MatrixTests +/** + * @brief Collection of tests for abstract hiopMatrixDense implementations. + * + * This class contains implementation of all dense matrix unit tests and abstract + * interface for testing utility functions, which are specific to the particular + * matrix and vector implementations. + * + * To add a new test, simply add a new public method to this class and call it + * from function runTests implemented in file testMatrixDense.cpp. Use helper + * functions to abstract implementation specific details such as local data + * size and memory space, accessing local data elements, etc. + * + * If you want to add tests for a new dense matrix implementation (e.g. + * column-major), you will need to reimplement helper functions, as well. + * + * @warning HiOp distributed memory partitioning is 1-D and some of the unit + * tests here implicitly assume that. When and if HiOp MPI partitioning + * changes, these tests will have to be rewritten. + */ + +class MatrixTestsDense : public TestBase { public: MatrixTestsDense() {} virtual ~MatrixTestsDense(){} -private: + int matrixSetToZero(hiop::hiopMatrixDense& A, const int rank) + { + A.setToConstant(one); + A.setToZero(); + const int fail = verifyAnswer(&A, zero); + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + int matrixSetToConstant(hiop::hiopMatrixDense& A, const int rank) + { + A.setToConstant(one); + int fail = verifyAnswer(&A, one); + A.setToConstant(two); + fail += verifyAnswer(&A, two); + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + int matrixCopyFrom( + hiopMatrixDense &dst, + hiopMatrixDense &src, + const int rank) + { + assert(dst.n() == src.n() && "Did you pass in matrices of the same size?"); + assert(dst.m() == src.m() && "Did you pass in matrices of the same size?"); + assert(getNumLocRows(&dst) == getNumLocRows(&src) && "Did you pass in matrices of the same size?"); + assert(getNumLocCols(&dst) == getNumLocCols(&src) && "Did you pass in matrices of the same size?"); + const real_type src_val = one; + + // Test copying src another matrix + src.setToConstant(src_val); + dst.setToZero(); + + dst.copyFrom(src); + int fail = verifyAnswer(&dst, src_val); + + // test copying src a raw buffer + const size_t buf_len = getNumLocRows(&src) * getNumLocCols(&src); + const real_type* src_buf = getLocalDataConst(&src); + dst.setToZero(); + + dst.copyFrom(src_buf); + fail += verifyAnswer(&dst, src_val); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &dst); + } + + /* + * y_{glob} \leftarrow \beta y_{glob} + \alpha A_{glob \times loc} x_{loc} + */ + int matrixTimesVec( + hiop::hiopMatrixDense& A, + hiop::hiopVector& y, + hiop::hiopVector& x, + const int rank=0) + { + assert(getLocalSize(&y) == getNumLocRows(&A) && "Did you pass in vectors of the correct sizes?"); + assert(getLocalSize(&x) == getNumLocCols(&A) && "Did you pass in vectors of the correct sizes?"); + const real_type alpha = one; + const real_type beta = one; + const real_type A_val = one; + const real_type y_val = three; + const real_type x_val = three; + const real_type N_glob = static_cast(A.n()); + int fail = 0; + + y.setToConstant(y_val); + x.setToConstant(x_val); + A.setToConstant(A_val); + + A.timesVec(beta, y, alpha, x); + + real_type expected = (beta * y_val) + (alpha * A_val * x_val * N_glob); + fail += verifyAnswer(&y, expected); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /* + * y = beta * y + alpha * A^T * x + * + * Notice that since A^T, x must not be distributed in this case, whereas + * the plain `timesVec' nessecitated that x be distributed and y not be. + */ + int matrixTransTimesVec( + hiop::hiopMatrixDense& A, + hiop::hiopVector& x, + hiop::hiopVector& y, + const int rank=0) + { + const local_ordinal_type M = getNumLocRows(&A); + const local_ordinal_type N = getNumLocCols(&A); + + assert(getLocalSize(&x) == getNumLocRows(&A) && "Did you pass in vectors of the correct sizes?"); + assert(getLocalSize(&y) == getNumLocCols(&A) && "Did you pass in vectors of the correct sizes?"); + const real_type alpha = one; + const real_type beta = one; + const real_type A_val = one; + const real_type y_val = three; + const real_type x_val = three; + // Take m() because A will be transposed + const real_type N_glob = static_cast(A.m()); + int fail = 0; + + // Index of row of A that will be set to zero, + // and index of y that will be beta * y_val + const local_ordinal_type index_to_zero = N-1; + + A.setToConstant(A_val); + y.setToConstant(y_val); + x.setToConstant(x_val); + + /* + * Zero a row of A^T to test that the resulting vector + * has its initial value as the first element, ensuring that + * the matrix is correctly transposed. + */ + for (int i=0; i real_type + { + const bool isZerodRow = (i == index_to_zero); + return isZerodRow ? + beta * y_val : + (beta * y_val) + (alpha * A_val * x_val * N_glob); + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /** + * W = beta * W + alpha * A * M + * + * Shapes: + * A: KxM + * M: MxN + * W: KxN + * all local + */ + int matrixTimesMat( + hiop::hiopMatrixDense& A, + hiop::hiopMatrixDense& X, + hiop::hiopMatrixDense& W, + const int rank=0) + { + const local_ordinal_type K = getNumLocCols(&A); + assert(K == A.n()); + assert(getNumLocCols(&X) == X.n()); + assert(K == getNumLocRows(&X)); + assert(getNumLocRows(&A) == getNumLocRows(&W)); + assert(getNumLocCols(&X) == getNumLocCols(&W)); + const real_type A_val = two, + X_val = three, + W_val = two, + alpha = two, + beta = two; + + A.setToConstant(A_val); + W.setToConstant(W_val); + X.setToConstant(X_val); + A.timesMat(beta, W, alpha, X); + real_type expected = (beta * W_val) + (alpha * A_val * X_val * K); + + const int fail = verifyAnswer(&W, expected); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /* + * W = beta * W + alpha * this^T * X + * + * A: kxm local + * W: mxn + * X: kxn + * + */ + int matrixTransTimesMat( + hiop::hiopMatrixDense& A_local, + hiop::hiopMatrixDense& W, + hiop::hiopMatrixDense& X, + const int rank) + { + const local_ordinal_type K = getNumLocRows(&A_local); + const global_ordinal_type N_loc = getNumLocCols(&X); + assert(getNumLocCols(&A_local) == getNumLocRows(&W) && "Matrices have mismatched shapes"); + assert(X.n() == W.n() && "Matrices have mismatched shapes"); + assert(N_loc == getNumLocCols(&W) && "Matrices have mismatched shapes"); + assert(K == getNumLocRows(&X) && "Matrices have mismatched shapes"); + const real_type A_val = two, + X_val = three, + W_val = two, + alpha = two, + beta = two; + + /* + * One row of X will be set to zero to ensure + * the matrix multiply and transpose operations are + * working correctly. + */ + const int idx_of_zero_row = K - 1; + + A_local.setToConstant(A_val); + W.setToConstant(W_val); + X.setToConstant(X_val); + + // X[idx][:] = 0 + for (int i=0; i(A.n()); + + A.setToConstant(A_val); + W_local.setToConstant(W_val); + X.setToConstant(X_val); + + // Set a row of X to zero + local_ordinal_type idx_of_zero_row = getNumLocRows(&X) - 1; + setLocalRow(&X, idx_of_zero_row, zero); + + A.timesMatTrans(beta, W_local, alpha, X); + + // Column of W with second term equal to zero + local_ordinal_type idx_of_zero_col = getNumLocCols(&W_local) - 1; + int fail = verifyAnswer(&W_local, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + return j == idx_of_zero_col ? (beta * W_val) : (beta * W_val) + (alpha * A_val * X_val * Nglob); + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /* + * this += alpha * diag + */ + int matrixAddDiagonal( + hiop::hiopMatrixDense& A, + hiop::hiopVector& x, + const int rank=0) + { + int fail = 0; + assert(getNumLocCols(&A) == getLocalSize(&x)); + assert(getNumLocRows(&A) == getLocalSize(&x)); + assert(getNumLocRows(&A) == A.n()); + assert(A.n() == x.get_size()); + assert(A.m() == x.get_size()); + static const real_type alpha = two, + A_val = quarter, + x_val = half; + + A.setToConstant(A_val); + x.setToConstant(x_val); + A.addDiagonal(alpha, x); + fail += verifyAnswer(&A, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + const bool isOnDiagonal = (i == j); + return isOnDiagonal ? A_val + x_val * alpha : A_val; + }); + + A.setToConstant(A_val); + A.addDiagonal(alpha); + fail += verifyAnswer(&A, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + const bool isOnDiagonal = (i == j); + return isOnDiagonal ? A_val + alpha : A_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /** + * @breif this += alpha * subdiag + * + * @note this test checks all three overloads: + * - addSubDiagonal(const double&, long long, const hiopVector&) + * - addSubDiagonal(int, const double&, const hiopVector&, int, int) + * - addSubDiagonal(int, int, const double&) + */ + int matrixAddSubDiagonal( + hiop::hiopMatrixDense& A, + hiop::hiopVector& x, + const int rank=0) + { + int fail = 0; + const local_ordinal_type N = getNumLocCols(&A); + const local_ordinal_type x_len = getLocalSize(&x); + const real_type alpha = half; + const real_type A_val = half; + const real_type x_val = one; + assert(N == A.n() && "Test should only be ran sequentially."); + assert(N == A.m() && "Test should only run with symmetric matrices."); + + // Test the overload that assumes the entire source vector + // will be added to the subdiagonal + local_ordinal_type start_idx = N - x_len; + + A.setToConstant(A_val); + x.setToConstant(x_val); + A.addSubDiagonal(alpha, start_idx, x); + fail += verifyAnswer(&A, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + const bool isOnSubDiagonal = (i>=start_idx && i==j); + return isOnSubDiagonal ? A_val + x_val * alpha : A_val; + }); + + // We're only going to add n-1 elements of the vector + // Test the overload that specifies subset of the vector + // to be added to subdiagonal + local_ordinal_type start_idx_src = 1; + local_ordinal_type num_elements_to_add = x_len - start_idx_src; + local_ordinal_type start_idx_dest = (N - x_len) + start_idx_src; + + A.setToConstant(A_val); + x.setToConstant(x_val); + A.addSubDiagonal(start_idx_dest, alpha, x, start_idx_src, num_elements_to_add); + + fail += verifyAnswer(&A, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + const bool isOnSubDiagonal = (i>=start_idx_dest && i==j); + return isOnSubDiagonal ? A_val + x_val * alpha : A_val; + }); + + // Operating on N-2 elements s.t. the first and last elements of the sub + // diagonal are not operated on. + start_idx_dest = 1; + const double c = two; + const int num_elems = N - 2; + A.setToConstant(A_val); + A.addSubDiagonal(start_idx_dest, num_elems, c); + fail += verifyAnswer(&A, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + const bool isOperatedOn = i >= start_idx_dest && + i == j && + i < start_idx_dest + num_elems; + return isOperatedOn ? A_val + c : A_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /* + * A += alpha * B + */ + int matrixAddMatrix( + hiop::hiopMatrixDense& A, + hiop::hiopMatrixDense& B, + const int rank) + { + assert(getNumLocRows(&A) == getNumLocRows(&B)); + assert(getNumLocCols(&A) == getNumLocCols(&B)); + const real_type alpha = half, + A_val = half, + B_val = one; + + A.setToConstant(A_val); + B.setToConstant(B_val); + A.addMatrix(alpha, B); + const int fail = verifyAnswer(&A, A_val + B_val * alpha); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /* + * Block of W += alpha*A + * + * Block of W summed with A is in the trasposed + * location of the same call to addToSymDenseMatrixUpperTriangle + * + * Precondition: W is square + */ + int matrixTransAddToSymDenseMatrixUpperTriangle( + hiop::hiopMatrixDense& W, + hiop::hiopMatrixDense& A, + const int rank=0) + { + const local_ordinal_type N_loc = getNumLocCols(&W); + const local_ordinal_type A_M = getNumLocRows(&A); + const local_ordinal_type A_N_loc = getNumLocCols(&A); + assert(W.m() == W.n()); + assert(getNumLocRows(&W) >= getNumLocRows(&A)); + assert(W.n() >= A.n()); + + const local_ordinal_type start_idx_row = 0; + const local_ordinal_type start_idx_col = N_loc - A_M; + const real_type alpha = half, + A_val = half, + W_val = one; + + A.setToConstant(A_val); + W.setToConstant(W_val); + A.transAddToSymDenseMatrixUpperTriangle(start_idx_row, start_idx_col, alpha, W); + const int fail = verifyAnswer(&W, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + const bool isTransUpperTriangle = ( + i>=start_idx_row && i=start_idx_col && j= A.n()); + assert(getNumLocCols(&A) <= getNumLocCols(&W)); + + // Map the upper triangle of A to W starting + // at W's upper left corner + const local_ordinal_type diag_start = 0; + int fail = 0; + const real_type alpha = half, + A_val = half, + W_val = one; + + A.setToConstant(A_val); + W.setToConstant(W_val); + A.addUpperTriangleToSymDenseMatrixUpperTriangle(diag_start, alpha, W); + fail += verifyAnswer(&W, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + bool isUpperTriangle = (i>=diag_start && i=i && j real_type + { + // Rows are always global in HiOp (for now) + auto irow = static_cast(i); + (void)j; // j is unused + const bool isLastRow = (irow == init_num_rows); + return isLastRow ? vec_val : A_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + /** + * Tests function that copies rows from source to destination starting from + * `dst_start_idx` in the same order. + * + */ + int matrixCopyRowsFrom( + hiopMatrixDense& dst, + hiopMatrixDense& src, + const int rank) + { + assert(dst.n() == src.n()); + assert(dst.m() > src.m()); + assert(getNumLocCols(&dst) == getNumLocCols(&src)); + assert(getNumLocRows(&dst) > getNumLocRows(&src)); + const real_type dst_val = one; + const real_type src_val = two; + const local_ordinal_type src_num_rows = getNumLocRows(&src); + local_ordinal_type num_rows_to_copy = src_num_rows; + const local_ordinal_type dst_start_idx = getNumLocRows(&dst) - src_num_rows; + + // Test copying continuous rows from matrix + dst.setToConstant(dst_val); + src.setToConstant(src_val); + + dst.copyRowsFrom(src, num_rows_to_copy, dst_start_idx); + + int fail = verifyAnswer(&dst, + [=](local_ordinal_type i, local_ordinal_type j) -> real_type + { + (void)j; // j is unused + const bool isRowCopiedOver = ( + i >= dst_start_idx && + i < dst_start_idx + src_num_rows); + return isRowCopiedOver ? src_val : dst_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &dst); + } + + /** + * Tests function that copies rows from source to destination in order + * specified by index array `row_idxs`. + * + */ + int matrixCopyRowsFromSelect( + hiopMatrixDense& dst, + hiopMatrixDense& src, + const int rank) + { + assert(dst.n() == src.n()); + assert(getNumLocCols(&dst) == getNumLocCols(&src)); + const real_type dst_val = one; + const real_type src_val = two; + const local_ordinal_type num_rows_to_copy = getNumLocRows(&dst); + assert(num_rows_to_copy <= src.m()); + + // Test copying continuous rows from matrix + dst.setToConstant(dst_val); + src.setToConstant(src_val); + global_ordinal_type *row_idxs = new global_ordinal_type[num_rows_to_copy]; + for (global_ordinal_type i = 0; i < num_rows_to_copy; ++i) + row_idxs[i] = i; + row_idxs[0] = num_rows_to_copy - 1; + row_idxs[num_rows_to_copy - 1] = 0; + setLocalRow(&src, num_rows_to_copy - 1, zero); + + dst.copyRowsFrom(src, row_idxs, num_rows_to_copy); + + int fail = verifyAnswer(&dst, + [=](local_ordinal_type i, local_ordinal_type j) -> real_type + { + (void)j; // j is unused + return i == 0 ? zero : src_val; + }); + + delete [] row_idxs; + printMessage(fail, __func__, rank); + return reduceReturn(fail, &dst); + } + + int matrixCopyBlockFromMatrix( + hiopMatrixDense& src, + hiopMatrixDense& dst, + const int rank=0) + { + assert(src.n() < dst.n() + && "Src mat must be smaller than dst mat"); + assert(src.m() < dst.m() + && "Src mat must be smaller than dst mat"); + assert(getNumLocCols(&src) < getNumLocCols(&dst) + && "Src mat must be smaller than dst mat"); + const real_type src_val = one; + const real_type dst_val = two; + + // Copy matrix block into downmost and rightmost location + // possible + const local_ordinal_type src_num_rows = getNumLocRows(&src); + const local_ordinal_type src_num_cols = getNumLocCols(&src); + const local_ordinal_type dst_start_row = getNumLocRows(&dst) - src_num_rows; + const local_ordinal_type dst_start_col = getNumLocCols(&dst) - src_num_cols; + + src.setToConstant(src_val); + dst.setToConstant(dst_val); + dst.copyBlockFromMatrix(dst_start_row, dst_start_col, src); + + const int fail = verifyAnswer(&dst, + [=](local_ordinal_type i, local_ordinal_type j) -> real_type + { + const bool isIdxCopiedFromSource = ( + i >= dst_start_row && i < dst_start_row + src_num_rows && + j >= dst_start_col && j < dst_start_col + src_num_cols); + return isIdxCopiedFromSource ? src_val : dst_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &dst); + } + + int matrixCopyFromMatrixBlock( + hiopMatrixDense& src, + hiopMatrixDense& dst, + const int rank=0) + { + assert(src.n() > dst.n() + && "Src mat must be larger than dst mat"); + assert(src.m() > dst.m() + && "Src mat must be larger than dst mat"); + assert(getNumLocCols(&src) > getNumLocCols(&dst) + && "Src mat must be larger than dst mat"); + const local_ordinal_type dst_m = getNumLocRows(&dst); + const local_ordinal_type dst_n = getNumLocCols(&dst); + const local_ordinal_type src_m = getNumLocRows(&src); + const local_ordinal_type src_n = getNumLocCols(&src); + const local_ordinal_type block_start_row = (src_m - getNumLocRows(&dst)) - 1; + const local_ordinal_type block_start_col = (src_n - getNumLocCols(&dst)) - 1; + + const real_type src_val = one; + const real_type dst_val = two; + src.setToConstant(src_val); + if (rank == 0) + setLocalElement(&src, src_m - 1, src_n - 1, zero); + dst.setToConstant(dst_val); + + dst.copyFromMatrixBlock(src, block_start_row, block_start_col); + + const int fail = verifyAnswer(&dst, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + // This is the element set to zero in src + // before being copied over + if (i == dst_m && j == dst_n && rank == 0) + return zero; + else + return src_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &dst); + } + + /** + * shiftRows does not overwrite rows in the opposite direction + * they are shifted. For example + * @verbatim + * 2 2 2 2 2 2 + * 1 1 1 1 1 1 + * 1 1 1 shiftRows(2) -> 2 2 2 + * @endverbatim + * The uppermost row is not overwritten by the 1-row that would + * wrap around and replace it. + */ + int matrixShiftRows( + hiopMatrixDense& A, + const int rank) + { + const local_ordinal_type M = getNumLocRows(&A); + local_ordinal_type uniq_row_idx = 0; + local_ordinal_type shift = M - 1; + int fail = 0; + + const real_type A_val = one; + const real_type uniq_row_val = two; + A.setToConstant(A_val); + + // Set one row to a unique value + setLocalRow(&A, uniq_row_idx, uniq_row_val); + A.shiftRows(shift); + + fail += verifyAnswer(&A, + [=](local_ordinal_type i, local_ordinal_type j) -> real_type + { + (void)j; // j is unused + const bool isUniqueRow = ( + i == (uniq_row_idx + shift) || + i == uniq_row_idx); + return isUniqueRow ? uniq_row_val : A_val; + }); + + // Now check negative shift + shift *= -1; + uniq_row_idx = M - 1; + A.setToConstant(A_val); + setLocalRow(&A, uniq_row_idx, uniq_row_val); + A.shiftRows(shift); + + fail += verifyAnswer(&A, + [=] (local_ordinal_type i, local_ordinal_type j) -> real_type + { + (void)j; // j is unused + const bool isUniqueRow = ( + i == (uniq_row_idx + shift) || + i == uniq_row_idx); + return isUniqueRow ? uniq_row_val : A_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + int matrixReplaceRow( + hiopMatrixDense& A, + hiopVector& vec, + const int rank) + { + const local_ordinal_type M = getNumLocRows(&A); + assert(getNumLocCols(&A) == vec.get_local_size() && "Did you pass a vector and matrix of compatible lengths?"); + assert(A.n() == vec.get_size() && "Did you pass a vector and matrix of compatible lengths?"); + + const local_ordinal_type row_idx = M - 1; + const local_ordinal_type col_idx = 1; + const real_type A_val = one; + const real_type vec_val = two; + A.setToConstant(A_val); + vec.setToConstant(vec_val); + setLocalElement(&vec, col_idx, zero); + + A.replaceRow(row_idx, vec); + const int fail = verifyAnswer(&A, + [=](local_ordinal_type i, local_ordinal_type j) -> real_type + { + // Was the row replaced? + if (i == row_idx) + { + // Was the value at col_idx set to zero? + if (j == col_idx) + return zero; + else + return vec_val; + } + // The matrix should be otherwise unchanged. + else + { + return A_val; + } + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + + int matrixGetRow( + hiopMatrixDense& A, + hiopVector& vec, + const int rank) + { + const local_ordinal_type N = getNumLocCols(&A); + const local_ordinal_type M = getNumLocRows(&A); + assert(N == vec.get_local_size() && "Did you pass a vector and matrix of compatible lengths?"); + assert(A.n() == vec.get_size() && "Did you pass a vector and matrix of compatible lengths?"); + + // Set one value in the matrix row to be retrieved to be a unique value + const local_ordinal_type row_idx = M - 1; + const local_ordinal_type col_idx = N - 1; + const real_type A_val = one; + const real_type vec_val = two; + A.setToConstant(A_val); + if (rank == 0) + setLocalElement(&A, row_idx, col_idx, zero); + vec.setToConstant(vec_val); + A.getRow(row_idx, vec); + + const int fail = verifyAnswer(&vec, + [=](local_ordinal_type i) -> real_type + { + if (rank == 0 && i == col_idx) + return zero; + else + return A_val; + }); + + printMessage(fail, __func__, rank); + return reduceReturn(fail, &A); + } + +#ifdef HIOP_DEEPCHECKS + int matrixAssertSymmetry( + hiop::hiopMatrixDense& A, + const int rank=0) + { + const local_ordinal_type M = getNumLocRows(&A); + const local_ordinal_type N = getNumLocCols(&A); + int fail = 0; + + assert(A.m() == A.n()); + A.setToConstant(one); + fail += !A.assertSymmetry(eps); + + // Set first row and column to zero globally + for (int i=0; i expect) override; - virtual int verifyAnswer(hiop::hiopVector *x, real_type answer) override; + const real_type val) = 0; + virtual real_type getLocalElement( + const hiop::hiopMatrixDense* a, + local_ordinal_type i, + local_ordinal_type j) = 0; + virtual const real_type* getLocalDataConst(hiop::hiopMatrixDense* a) = 0; + virtual int verifyAnswer(hiop::hiopMatrixDense* A, real_type answer) = 0; virtual int verifyAnswer( - hiop::hiopVector *x, - std::function expect) override; - virtual bool reduceReturn(int failures, hiop::hiopMatrixDense* A) override; - virtual bool globalToLocalMap( hiop::hiopMatrixDense* A, - const global_ordinal_type row, - const global_ordinal_type col, - local_ordinal_type &local_row, - local_ordinal_type &local_col) override; + std::function expect) = 0; + virtual bool reduceReturn(int failures, hiop::hiopMatrixDense* A) = 0; -#ifdef HIOP_USE_MPI - MPI_Comm getMPIComm(hiop::hiopMatrixDense* A); -#endif + // Vector helper function + virtual void setLocalElement( + hiop::hiopVector *_x, + const local_ordinal_type i, + const real_type val) = 0; + virtual real_type getLocalElement( + const hiop::hiopVector* x, + local_ordinal_type i) = 0; + virtual local_ordinal_type getLocalSize(const hiop::hiopVector* x) = 0; + virtual int verifyAnswer(hiop::hiopVector* x, real_type answer) = 0; + virtual int verifyAnswer( + hiop::hiopVector* x, + std::function expect) = 0; }; -}} // namespace hiop::tests +}} // namespace hiop{ namespace tests{ diff --git a/tests/LinAlg/matrixTestsDense.cpp b/tests/LinAlg/matrixTestsDenseRowMajor.cpp similarity index 53% rename from tests/LinAlg/matrixTestsDense.cpp rename to tests/LinAlg/matrixTestsDenseRowMajor.cpp index 668200949..b472198ba 100644 --- a/tests/LinAlg/matrixTestsDense.cpp +++ b/tests/LinAlg/matrixTestsDenseRowMajor.cpp @@ -47,140 +47,117 @@ // product endorsement purposes. /** - * @file matrixTestsDense.cpp + * @file matrixTestsDenseRowMajor.cpp * * @author Asher Mancinelli , PNNL * @author Slaven Peles , PNNL + * @author Robert Rutherford , PNNL * */ #include -#include "matrixTestsDense.hpp" +#include "matrixTestsDenseRowMajor.hpp" namespace hiop { namespace tests { -/// Method to set matrix _A_ element (i,j) to _val_. -/// First need to retrieve hiopMatrixDense from the abstract interface -void MatrixTestsDense::setLocalElement( +// +// Matrix helper methods +// + +/// Get number of rows in local data block of matrix _A_ +local_ordinal_type MatrixTestsDenseRowMajor::getNumLocRows(const hiop::hiopMatrixDense* A) +{ + const auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + + // get_local_size_m returns global ordinal type! HiOp issue? + return static_cast(amat->get_local_size_m()); + // ^^^ +} + +/// Get number of columns in local data block of matrix _A_ +local_ordinal_type MatrixTestsDenseRowMajor::getNumLocCols(const hiop::hiopMatrixDense* A) +{ + const auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + + // Local sizes should be returned as local ordinal type + return static_cast(amat->get_local_size_n()); + // ^^^ +} + +/// Set local data element (i,j) of matrix _A_ to _val_. +void MatrixTestsDenseRowMajor::setLocalElement( hiop::hiopMatrixDense* A, local_ordinal_type i, local_ordinal_type j, real_type val) { - hiop::hiopMatrixDense* amat = dynamic_cast(A); - if(amat != nullptr) - { - real_type* data = amat->local_data(); - //data[i][j] = val; - data[i*amat->get_local_size_n()+j] = val; - } - else THROW_NULL_DEREF; -} + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; -void MatrixTestsDense::setLocalElement( - hiop::hiopVector* _x, - const local_ordinal_type i, - const real_type val) -{ - auto x = dynamic_cast(_x); - if(x != nullptr) - { - real_type* data = x->local_data(); - data[i] = val; - } - else THROW_NULL_DEREF; + real_type* data = amat->local_data(); + local_ordinal_type ncols = getNumLocCols(A); + //data[i][j] = val; + data[i*ncols + j] = val; } -/// Method to set a single row of matrix to a constant value -void MatrixTestsDense::setLocalRow( +/// Method to set a single local row of matrix to a constant value +void MatrixTestsDenseRowMajor::setLocalRow( hiop::hiopMatrixDense* A, const local_ordinal_type row, const real_type val) { - const local_ordinal_type N = getNumLocCols(A); + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + + const local_ordinal_type N = getNumLocCols(amat); for (int i=0; i(A); - if(amat != nullptr) - //return amat->local_data_const()[i][j]; - return amat->local_data_const()[i*amat->get_local_size_n()+j]; - else THROW_NULL_DEREF; -} - -/// Returns element _i_ of vector _x_. -/// First need to retrieve hiopVectorPar from the abstract interface -real_type MatrixTestsDense::getLocalElement( - const hiop::hiopVector* x, - local_ordinal_type i) -{ - const hiop::hiopVectorPar* xvec = dynamic_cast(x); - if(xvec != nullptr) - return xvec->local_data_const()[i]; - else THROW_NULL_DEREF; -} + const auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; -local_ordinal_type MatrixTestsDense::getNumLocRows(hiop::hiopMatrixDense* A) -{ - hiop::hiopMatrixDense* amat = dynamic_cast(A); - if(amat != nullptr) - return amat->get_local_size_m(); - // ^^^ - else THROW_NULL_DEREF; + const real_type* data = amat->local_data_const(); + local_ordinal_type ncols = getNumLocCols(A); + return data[i*ncols + j]; } -local_ordinal_type MatrixTestsDense::getNumLocCols(hiop::hiopMatrixDense* A) +/// Get MPI communicator of matrix _A_ +MPI_Comm MatrixTestsDenseRowMajor::getMPIComm(hiop::hiopMatrixDense* A) { - hiop::hiopMatrixDense* amat = dynamic_cast(A); - if(amat != nullptr) - return amat->get_local_size_n(); - // ^^^ - else THROW_NULL_DEREF; -} + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; -/// Returns size of local data array for vector _x_ -int MatrixTestsDense::getLocalSize(const hiop::hiopVector* x) -{ - const hiop::hiopVectorPar* xvec = dynamic_cast(x); - if(xvec != nullptr) - return static_cast(xvec->get_local_size()); - else THROW_NULL_DEREF; + return amat->get_mpi_comm(); } -#ifdef HIOP_USE_MPI -/// Get communicator -MPI_Comm MatrixTestsDense::getMPIComm(hiop::hiopMatrixDense* _A) +/// Returns const pointer to local data block of matrix _A_. +const real_type* MatrixTestsDenseRowMajor::getLocalDataConst(hiop::hiopMatrixDense* A) { - const hiop::hiopMatrixDense* A = dynamic_cast(_A); - if(A != nullptr) - return A->get_mpi_comm(); - else THROW_NULL_DEREF; -} -#endif + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; -/// Returns pointer to local data block of matrix _A_. -/// First need to retrieve hiopMatrixDenseRowMajor from the abstract interface -real_type* MatrixTestsDense::getLocalData(hiop::hiopMatrixDense* A) -{ - auto* amat = dynamic_cast(A); - if(amat != nullptr) - { - return amat->local_data(); - } - else THROW_NULL_DEREF; + return amat->local_data_const(); } -// Every rank returns failure if any individual rank fails -bool MatrixTestsDense::reduceReturn(int failures, hiop::hiopMatrixDense* A) +/// Reduce return output: Every rank returns failure if any individual rank fails +bool MatrixTestsDenseRowMajor::reduceReturn(int failures, hiop::hiopMatrixDense* A) { int fail = 0; @@ -194,19 +171,23 @@ bool MatrixTestsDense::reduceReturn(int failures, hiop::hiopMatrixDense* A) return (fail != 0); } - [[nodiscard]] -int MatrixTestsDense::verifyAnswer(hiop::hiopMatrixDense* A, const double answer) +/// Verify matrix elements are set to `answer`. +[[nodiscard]] +int MatrixTestsDenseRowMajor::verifyAnswer(hiop::hiopMatrixDense* A, const double answer) { - const local_ordinal_type M = getNumLocRows(A); - const local_ordinal_type N = getNumLocCols(A); + local_ordinal_type mrows = getNumLocRows(A); + local_ordinal_type ncols = getNumLocCols(A); + int fail = 0; - for (local_ordinal_type i=0; i expect) { - const local_ordinal_type M = getNumLocRows(A); - const local_ordinal_type N = getNumLocCols(A); + local_ordinal_type mrows = getNumLocRows(A); + local_ordinal_type ncols = getNumLocCols(A); + int fail = 0; - for (local_ordinal_type i=0; i(x); + if(xvec == nullptr) + THROW_NULL_DEREF; + + return static_cast(xvec->get_local_size()); +} + +/// Sets a local data element of vector _x_ +void MatrixTestsDenseRowMajor::setLocalElement( + hiop::hiopVector* x, + const local_ordinal_type i, + const real_type val) +{ + auto* xvec = dynamic_cast(x); + if(xvec == nullptr) + THROW_NULL_DEREF; + + real_type* data = x->local_data(); + data[i] = val; +} + +/// Returns local data element _i_ of vector _x_. +real_type MatrixTestsDenseRowMajor::getLocalElement( + const hiop::hiopVector* x, + local_ordinal_type i) +{ + const auto* xvec = dynamic_cast(x); + if(xvec == nullptr) + THROW_NULL_DEREF; + + return xvec->local_data_const()[i]; +} + + /// Checks if _local_ vector elements are set to `answer`. - [[nodiscard]] -int MatrixTestsDense::verifyAnswer(hiop::hiopVector* x, double answer) +[[nodiscard]] +int MatrixTestsDenseRowMajor::verifyAnswer(hiop::hiopVector* x, double answer) { const local_ordinal_type N = getLocalSize(x); @@ -259,8 +283,9 @@ int MatrixTestsDense::verifyAnswer(hiop::hiopVector* x, double answer) return local_fail; } - [[nodiscard]] -int MatrixTestsDense::verifyAnswer( +/// Checks if _local_ vector elements match `expected` values. +[[nodiscard]] +int MatrixTestsDenseRowMajor::verifyAnswer( hiop::hiopVector* x, std::function expect) { @@ -277,37 +302,6 @@ int MatrixTestsDense::verifyAnswer( return local_fail; } -bool MatrixTestsDense::globalToLocalMap( - hiop::hiopMatrixDense* A, - const global_ordinal_type row, - const global_ordinal_type col, - local_ordinal_type& local_row, - local_ordinal_type& local_col) -{ -#ifdef HIOP_USE_MPI - int rank = 0; - MPI_Comm comm = getMPIComm(A); - MPI_Comm_rank(comm, &rank); - const local_ordinal_type n_local = getNumLocCols(A); - const global_ordinal_type local_col_start = n_local * rank; - if (col >= local_col_start && col < local_col_start + n_local) - { - local_row = row; - local_col = col % n_local; - return true; - } - else - { - return false; - } -#else - (void) A; // surpresses waring as A is not needed here without MPI - local_row = row; - local_col = col; - return true; -#endif -} - // End helper methods }} // namespace hiop::tests diff --git a/tests/LinAlg/matrixTestsDenseRowMajor.hpp b/tests/LinAlg/matrixTestsDenseRowMajor.hpp new file mode 100644 index 000000000..521ed3e4f --- /dev/null +++ b/tests/LinAlg/matrixTestsDenseRowMajor.hpp @@ -0,0 +1,111 @@ +// Copyright (c) 2017, Lawrence Livermore National Security, LLC. +// Produced at the Lawrence Livermore National Laboratory (LLNL). +// Written by Cosmin G. Petra, petra1@llnl.gov. +// LLNL-CODE-742473. All rights reserved. +// +// This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp +// is released under the BSD 3-clause license (https://opensource.org/licenses/BSD-3-Clause). +// Please also read “Additional BSD Notice” below. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// i. Redistributions of source code must retain the above copyright notice, this list +// of conditions and the disclaimer below. +// ii. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the documentation and/or +// other materials provided with the distribution. +// iii. Neither the name of the LLNS/LLNL nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Additional BSD Notice +// 1. This notice is required to be provided under our contract with the U.S. Department +// of Energy (DOE). This work was produced at Lawrence Livermore National Laboratory under +// Contract No. DE-AC52-07NA27344 with the DOE. +// 2. Neither the United States Government nor Lawrence Livermore National Security, LLC +// nor any of their employees, makes any warranty, express or implied, or assumes any +// liability or responsibility for the accuracy, completeness, or usefulness of any +// information, apparatus, product, or process disclosed, or represents that its use would +// not infringe privately-owned rights. +// 3. Also, reference herein to any specific commercial products, process, or services by +// trade name, trademark, manufacturer or otherwise does not necessarily constitute or +// imply its endorsement, recommendation, or favoring by the United States Government or +// Lawrence Livermore National Security, LLC. The views and opinions of authors expressed +// herein do not necessarily state or reflect those of the United States Government or +// Lawrence Livermore National Security, LLC, and shall not be used for advertising or +// product endorsement purposes. + +/** + * @file matrixTestsDenseRowMajor.hpp + * + * @author Asher Mancinelli , PNNL + * @author Slaven Peles , PNNL + * @author Robert Rutherford , PNNL + * + */ + +#pragma once + +#include "matrixTestsDense.hpp" +#include "hiopVectorPar.hpp" + +namespace hiop { namespace tests { + +class MatrixTestsDenseRowMajor : public MatrixTestsDense +{ +public: + MatrixTestsDenseRowMajor() {} + virtual ~MatrixTestsDenseRowMajor(){} + +private: + // Matrix helper methods + virtual local_ordinal_type getNumLocRows(const hiop::hiopMatrixDense* a) override; + virtual local_ordinal_type getNumLocCols(const hiop::hiopMatrixDense* a) override; + virtual void setLocalElement( + hiop::hiopMatrixDense* a, + local_ordinal_type i, + local_ordinal_type j, + real_type val) override; + virtual void setLocalRow( + hiop::hiopMatrixDense* A, + const local_ordinal_type row, + const real_type val) override; + virtual real_type getLocalElement( + const hiop::hiopMatrixDense* a, + local_ordinal_type i, + local_ordinal_type j) override; + virtual const real_type* getLocalDataConst(hiop::hiopMatrixDense* a) override; + virtual int verifyAnswer(hiop::hiopMatrixDense* A, real_type answer) override; + virtual int verifyAnswer( + hiop::hiopMatrixDense* A, + std::function expect) override; + MPI_Comm getMPIComm(hiop::hiopMatrixDense* A); + virtual bool reduceReturn(int failures, hiop::hiopMatrixDense* A) override; + + // Vector helper methods + virtual void setLocalElement( + hiop::hiopVector* x, + const local_ordinal_type i, + const real_type val) override; + virtual real_type getLocalElement( + const hiop::hiopVector* x, + local_ordinal_type i) override; + virtual local_ordinal_type getLocalSize(const hiop::hiopVector *x) override; + virtual int verifyAnswer(hiop::hiopVector *x, real_type answer) override; + virtual int verifyAnswer( + hiop::hiopVector *x, + std::function expect) override; +}; + +}} // namespace hiop::tests diff --git a/tests/LinAlg/matrixTestsRajaDense.cpp b/tests/LinAlg/matrixTestsRajaDense.cpp index bd2eb81d9..3c05c085b 100644 --- a/tests/LinAlg/matrixTestsRajaDense.cpp +++ b/tests/LinAlg/matrixTestsRajaDense.cpp @@ -51,6 +51,7 @@ * * @author Asher Mancinelli , PNNL * @author Slaven Peles , PNNL + * @author Robert Rutherford , PNNL * */ @@ -60,142 +61,108 @@ namespace hiop { namespace tests { -/// Method to set matrix _A_ element (i,j) to _val_. -/// First need to retrieve hiopMatrixDense from the abstract interface +// +// Matrix helper methods +// + +/// Get number of rows in local data block of matrix _A_ +local_ordinal_type MatrixTestsRajaDense::getNumLocRows(const hiop::hiopMatrixDense* A) +{ + const auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + + return amat->get_local_size_m(); + // ^^^ +} + +/// Get number of columns in local data block of matrix _A_ +local_ordinal_type MatrixTestsRajaDense::getNumLocCols(const hiop::hiopMatrixDense* A) +{ + const auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + + return amat->get_local_size_n(); + // ^^^ +} + +/// Set local data element (i,j) of matrix _A_ to _val_ in current memory space. void MatrixTestsRajaDense::setLocalElement( hiop::hiopMatrixDense* A, local_ordinal_type i, local_ordinal_type j, real_type val) { - hiop::hiopMatrixRajaDense* amat = dynamic_cast(A); - if(amat != nullptr) - { - amat->copyFromDev(); - real_type* data = amat->local_data_host(); - data[i*amat->get_local_size_n() + j] = val; - amat->copyToDev(); - } - else THROW_NULL_DEREF; -} + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; -void MatrixTestsRajaDense::setLocalElement( - hiop::hiopVector* xvec, - const local_ordinal_type i, - const real_type val) -{ - auto* x = dynamic_cast(xvec); - if(x != nullptr) - { - x->copyFromDev(); - real_type* data = x->local_data_host(); - data[i] = val; - x->copyToDev(); - } - else THROW_NULL_DEREF; + amat->copyFromDev(); + real_type* data = amat->local_data_host(); + local_ordinal_type ncols = getNumLocCols(A); + data[i*ncols + j] = val; + amat->copyToDev(); } -/// Method to set a single row of matrix to a constant value +/// Set a single local row of matrix to a constant value in current memory space. void MatrixTestsRajaDense::setLocalRow( - hiop::hiopMatrixDense* Amat, + hiop::hiopMatrixDense* A, const local_ordinal_type row, const real_type val) { - hiop::hiopMatrixRajaDense* A = dynamic_cast(Amat); + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + const local_ordinal_type N = getNumLocCols(A); - A->copyFromDev(); - real_type* local_data = A->local_data_host(); + amat->copyFromDev(); + real_type* data = amat->local_data_host(); for (int j=0; jcopyToDev(); + amat->copyToDev(); } -/// Returns element (i,j) of matrix _A_. -/// First need to retrieve hiopMatrixDense from the abstract interface +/// Returns by value local element (i,j) of matrix _A_. real_type MatrixTestsRajaDense::getLocalElement( const hiop::hiopMatrixDense* A, local_ordinal_type i, local_ordinal_type j) { - const hiop::hiopMatrixRajaDense* am = dynamic_cast(A); - hiop::hiopMatrixRajaDense* amat = const_cast(am); - if(amat != nullptr) - { - amat->copyFromDev(); - return amat->local_data_host()[i*amat->get_local_size_n() + j]; - } - else THROW_NULL_DEREF; -} + const auto* am = dynamic_cast(A); + if(am == nullptr) + THROW_NULL_DEREF; + auto* amat = const_cast(am); + if(amat == nullptr) + THROW_NULL_DEREF; -/// Returns element _i_ of vector _x_. -/// First need to retrieve hiopVectorPar from the abstract interface -real_type MatrixTestsRajaDense::getLocalElement( - const hiop::hiopVector* x, - local_ordinal_type i) -{ - const hiop::hiopVectorRajaPar* xvec_const = dynamic_cast(x); - hiop::hiopVectorRajaPar* xvec = const_cast(xvec_const); - if(xvec != nullptr) - { - xvec->copyFromDev(); - return xvec->local_data_host_const()[i]; - } - else THROW_NULL_DEREF; + amat->copyFromDev(); + const real_type* data = amat->local_data_host(); + local_ordinal_type ncols = getNumLocCols(A); + return data[i*ncols + j]; } -local_ordinal_type MatrixTestsRajaDense::getNumLocRows(hiop::hiopMatrixDense* A) +/// Get MPI communicator of matrix _A_ +MPI_Comm MatrixTestsRajaDense::getMPIComm(hiop::hiopMatrixDense* A) { - hiop::hiopMatrixDense* amat = dynamic_cast(A); - if(amat != nullptr) - return amat->get_local_size_m(); - // ^^^ - else THROW_NULL_DEREF; + const auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + return amat->get_mpi_comm(); } -local_ordinal_type MatrixTestsRajaDense::getNumLocCols(hiop::hiopMatrixDense* A) -{ - hiop::hiopMatrixDense* amat = dynamic_cast(A); - if(amat != nullptr) - return amat->get_local_size_n(); - // ^^^ - else THROW_NULL_DEREF; -} - -/// Returns size of local data array for vector _x_ -int MatrixTestsRajaDense::getLocalSize(const hiop::hiopVector* x) -{ - const hiop::hiopVectorRajaPar* xvec = dynamic_cast(x); - if(xvec != nullptr) - return static_cast(xvec->get_local_size()); - else THROW_NULL_DEREF; -} - -#ifdef HIOP_USE_MPI -/// Get communicator -MPI_Comm MatrixTestsRajaDense::getMPIComm(hiop::hiopMatrixDense* _A) -{ - const hiop::hiopMatrixDense* A = dynamic_cast(_A); - if(A != nullptr) - return A->get_mpi_comm(); - else THROW_NULL_DEREF; -} -#endif - -/// Returns pointer to local data block of matrix _A_. -/// First need to retrieve hiopMatrixRajaDense from the abstract interface -real_type* MatrixTestsRajaDense::getLocalData(hiop::hiopMatrixDense* A) +/// Returns pointer to local data block of matrix _A_ in current memory space. +const real_type* MatrixTestsRajaDense::getLocalDataConst(hiop::hiopMatrixDense* A) { - hiop::hiopMatrixRajaDense* amat = dynamic_cast(A); - if(amat != nullptr) - { - return amat->local_data(); - } - else THROW_NULL_DEREF; + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + return amat->local_data_const(); } -// Every rank returns failure if any individual rank fails +/// Reduce return output: Every rank returns failure if any individual rank fails bool MatrixTestsRajaDense::reduceReturn(int failures, hiop::hiopMatrixDense* A) { int fail = 0; @@ -210,26 +177,32 @@ bool MatrixTestsRajaDense::reduceReturn(int failures, hiop::hiopMatrixDense* A) return (fail != 0); } - [[nodiscard]] -int MatrixTestsRajaDense::verifyAnswer(hiop::hiopMatrixDense* Amat, const double answer) +/// Verify matrix elements are set to `answer`. +[[nodiscard]] +int MatrixTestsRajaDense::verifyAnswer(hiop::hiopMatrixDense* A, const double answer) { - hiop::hiopMatrixRajaDense* A = dynamic_cast(Amat); - const local_ordinal_type M = getNumLocRows(A); - const local_ordinal_type N = getNumLocCols(A); + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + const local_ordinal_type M = getNumLocRows(amat); + const local_ordinal_type N = getNumLocCols(amat); // Copy data to the host mirror - A->copyFromDev(); - // Get array of pointers to dense matrix rows - double* local_matrix_data = A->local_data_host(); + amat->copyFromDev(); + // Get pointer to dense matrix local data on the host + const real_type* local_matrix_data = amat->local_data_host(); int fail = 0; + // RAJA matrix is stored in row-major format for (local_ordinal_type i=0; i expect) { - // const local_ordinal_type M = getNumLocRows(A); - // const local_ordinal_type N = getNumLocCols(A); - hiop::hiopMatrixRajaDense* A = dynamic_cast(Amat); - const local_ordinal_type M = getNumLocRows(A); - const local_ordinal_type N = getNumLocCols(A); + auto* amat = dynamic_cast(A); + if(amat == nullptr) + THROW_NULL_DEREF; + const local_ordinal_type M = getNumLocRows(amat); + const local_ordinal_type N = getNumLocCols(amat); // Copy data to the host mirror - A->copyFromDev(); - // Get array of pointers to dense matrix rows - double* local_matrix_data = A->local_data_host(); - + amat->copyFromDev(); + // Get pointer to dense matrix local data on the host + const real_type* local_matrix_data = amat->local_data_host(); + int fail = 0; for (local_ordinal_type i=0; i(x); + if(xvec == nullptr) + THROW_NULL_DEREF; + + return xvec->get_local_size(); +} + +/// Sets a local data element of vector _x_ in current memory space +void MatrixTestsRajaDense::setLocalElement( + hiop::hiopVector* x, + const local_ordinal_type i, + const real_type val) +{ + auto* xvec = dynamic_cast(x); + if(xvec == nullptr) + THROW_NULL_DEREF; + + xvec->copyFromDev(); + real_type* data = xvec->local_data_host(); + data[i] = val; + xvec->copyToDev(); +} + +/// Returns local data element _i_ of vector _x_ by value on the host. +real_type MatrixTestsRajaDense::getLocalElement( + const hiop::hiopVector* x, + local_ordinal_type i) +{ + const auto* xv = dynamic_cast(x); + if(xv == nullptr) + THROW_NULL_DEREF; + auto* xvec = const_cast(xv); + if(xvec == nullptr) + THROW_NULL_DEREF; + + xvec->copyFromDev(); + return xvec->local_data_host_const()[i]; +} + /// Checks if _local_ vector elements are set to `answer`. - [[nodiscard]] -int MatrixTestsRajaDense::verifyAnswer(hiop::hiopVector* xvec, double answer) +[[nodiscard]] +int MatrixTestsRajaDense::verifyAnswer(hiop::hiopVector* x, double answer) { - auto* x = dynamic_cast(xvec); - const local_ordinal_type N = getLocalSize(x); + auto* xvec = dynamic_cast(x); + if(xvec == nullptr) + THROW_NULL_DEREF; + + const local_ordinal_type N = getLocalSize(xvec); // Copy vector local data to the host mirror - x->copyFromDev(); + xvec->copyFromDev(); // Get raw pointer to the host mirror - const real_type* local_data = x->local_data_host_const(); + const real_type* local_data = xvec->local_data_host_const(); int local_fail = 0; for(local_ordinal_type i=0; i expect) { - auto* x = dynamic_cast(xvec); - const local_ordinal_type N = getLocalSize(x); + auto* xvec = dynamic_cast(x); + if(xvec == nullptr) + THROW_NULL_DEREF; + + const local_ordinal_type N = getLocalSize(xvec); // Copy vector local data to the host mirror - x->copyFromDev(); + xvec->copyFromDev(); // Get raw pointer to the host mirror - const real_type* local_data = x->local_data_host_const(); + const real_type* local_data = xvec->local_data_host_const(); int local_fail = 0; - for (int i=0; i= local_col_start && col < local_col_start + n_local) - { - local_row = row; - local_col = col % n_local; - return true; - } - else - { - return false; - } -#else - (void) A; // surpresses waring as A is not needed here without MPI - local_row = row; - local_col = col; - return true; -#endif -} - // End helper methods }} // namespace hiop::tests diff --git a/tests/LinAlg/matrixTestsRajaDense.hpp b/tests/LinAlg/matrixTestsRajaDense.hpp index f067a41a4..6627883d2 100644 --- a/tests/LinAlg/matrixTestsRajaDense.hpp +++ b/tests/LinAlg/matrixTestsRajaDense.hpp @@ -51,60 +51,60 @@ * * @author Asher Mancinelli , PNNL * @author Slaven Peles , PNNL + * @author Robert Rutherford , PNNL * */ #pragma once -#include "matrixTests.hpp" +#include "matrixTestsDense.hpp" #include "hiopVectorPar.hpp" namespace hiop { namespace tests { -class MatrixTestsRajaDense : public MatrixTests +class MatrixTestsRajaDense : public MatrixTestsDense { public: MatrixTestsRajaDense() {} virtual ~MatrixTestsRajaDense(){} private: + // Matrix helper methods + virtual local_ordinal_type getNumLocRows(const hiop::hiopMatrixDense* a) override; + virtual local_ordinal_type getNumLocCols(const hiop::hiopMatrixDense* a) override; virtual void setLocalElement( hiop::hiopMatrixDense* a, local_ordinal_type i, local_ordinal_type j, real_type val) override; - virtual void setLocalElement( - hiop::hiopVector* x, - const local_ordinal_type i, - const real_type val) override; virtual void setLocalRow( - hiop::hiopMatrixDense *A, + hiop::hiopMatrixDense* A, const local_ordinal_type row, const real_type val) override; - virtual real_type getLocalElement(const hiop::hiopMatrixDense* a, local_ordinal_type i, local_ordinal_type j) override; - virtual real_type getLocalElement(const hiop::hiopVector *x, local_ordinal_type i) override; - virtual local_ordinal_type getNumLocRows(hiop::hiopMatrixDense* a) override; - virtual local_ordinal_type getNumLocCols(hiop::hiopMatrixDense* a) override; - virtual local_ordinal_type getLocalSize(const hiop::hiopVector *x) override; - virtual real_type* getLocalData(hiop::hiopMatrixDense* a) override; + virtual real_type getLocalElement( + const hiop::hiopMatrixDense* a, + local_ordinal_type i, + local_ordinal_type j) override; + virtual const real_type* getLocalDataConst(hiop::hiopMatrixDense* a) override; virtual int verifyAnswer(hiop::hiopMatrixDense* A, real_type answer) override; virtual int verifyAnswer( hiop::hiopMatrixDense* A, std::function expect) override; + MPI_Comm getMPIComm(hiop::hiopMatrixDense* A); + virtual bool reduceReturn(int failures, hiop::hiopMatrixDense* A) override; + + // Vector helper methods + virtual void setLocalElement( + hiop::hiopVector* x, + const local_ordinal_type i, + const real_type val) override; + virtual real_type getLocalElement( + const hiop::hiopVector* x, + local_ordinal_type i) override; + virtual local_ordinal_type getLocalSize(const hiop::hiopVector *x) override; virtual int verifyAnswer(hiop::hiopVector *x, real_type answer) override; virtual int verifyAnswer( hiop::hiopVector *x, std::function expect) override; - virtual bool reduceReturn(int failures, hiop::hiopMatrixDense* A) override; - virtual bool globalToLocalMap( - hiop::hiopMatrixDense* A, - const global_ordinal_type row, - const global_ordinal_type col, - local_ordinal_type &local_row, - local_ordinal_type &local_col) override; - -#ifdef HIOP_USE_MPI - MPI_Comm getMPIComm(hiop::hiopMatrixDense* A); -#endif }; }} // namespace hiop::tests diff --git a/tests/LinAlg/vectorTestsPar.cpp b/tests/LinAlg/vectorTestsPar.cpp index 33c5b0822..e7aaa2cdc 100644 --- a/tests/LinAlg/vectorTestsPar.cpp +++ b/tests/LinAlg/vectorTestsPar.cpp @@ -63,23 +63,44 @@ namespace hiop { namespace tests { /// Returns const pointer to local vector data const real_type* VectorTestsPar::getLocalDataConst(const hiop::hiopVector* x) { - const hiop::hiopVectorPar* xvec = dynamic_cast(x); - return x->local_data_const(); + if(auto* xvec = dynamic_cast(x)) + { + return xvec->local_data_const(); + } + else + { + assert(false && "Wrong type of vector passed into `VectorTestsPar::getLocalDataConst`!"); + THROW_NULL_DEREF; + } } /// Method to set vector _x_ element _i_ to _value_. void VectorTestsPar::setLocalElement(hiop::hiopVector* x, local_ordinal_type i, real_type val) { - hiop::hiopVectorPar* xvec = dynamic_cast(x); - real_type *xdat = xvec->local_data(); - xdat[i] = val; + if(auto* xvec = dynamic_cast(x)) + { + real_type *xdat = xvec->local_data(); + xdat[i] = val; + } + else + { + assert(false && "Wrong type of vector passed into `VectorTestsPar::setLocalElement`!"); + THROW_NULL_DEREF; + } } /// Get communicator MPI_Comm VectorTestsPar::getMPIComm(hiop::hiopVector* x) { - const hiop::hiopVectorPar* xvec = dynamic_cast(x); - return xvec->get_mpi_comm(); + if(auto* xvec = dynamic_cast(x)) + { + return xvec->get_mpi_comm(); + } + else + { + assert(false && "Wrong type of vector passed into `VectorTestsPar::getMPIComm`!"); + THROW_NULL_DEREF; + } } /// Wrap new command diff --git a/tests/LinAlg/vectorTestsRajaPar.cpp b/tests/LinAlg/vectorTestsRajaPar.cpp index 11ce73055..bb1e24a3e 100644 --- a/tests/LinAlg/vectorTestsRajaPar.cpp +++ b/tests/LinAlg/vectorTestsRajaPar.cpp @@ -67,26 +67,47 @@ namespace hiop { namespace tests { /// Returns const pointer to local vector data const real_type* VectorTestsRajaPar::getLocalDataConst(const hiop::hiopVector* x_in) { - const hiop::hiopVectorRajaPar* x = dynamic_cast(x_in); - x->copyFromDev(); - return x->local_data_host_const(); + if(auto* x = dynamic_cast(x_in)) + { + x->copyFromDev(); + return x->local_data_host_const(); + } + else + { + assert(false && "Wrong type of vector passed into `VectorTestsRajaPar::getLocalDataConst`!"); + THROW_NULL_DEREF; + } } /// Method to set vector _x_ element _i_ to _value_. void VectorTestsRajaPar::setLocalElement(hiop::hiopVector* x_in, local_ordinal_type i, real_type val) { - hiop::hiopVectorRajaPar* x = dynamic_cast(x_in); - x->copyFromDev(); - real_type *xdat = x->local_data_host(); - xdat[i] = val; - x->copyToDev(); + if(auto* x = dynamic_cast(x_in)) + { + x->copyFromDev(); + real_type *xdat = x->local_data_host(); + xdat[i] = val; + x->copyToDev(); + } + else + { + assert(false && "Wrong type of vector passed into `VectorTestsRajaPar::setLocalElement`!"); + THROW_NULL_DEREF; + } } /// Get communicator MPI_Comm VectorTestsRajaPar::getMPIComm(hiop::hiopVector* x) { - const hiop::hiopVectorRajaPar* xvec = dynamic_cast(x); - return xvec->get_mpi_comm(); + if(auto* xvec = dynamic_cast(x)) + { + return xvec->get_mpi_comm(); + } + else + { + assert(false && "Wrong type of vector passed into `VectorTestsRajaPar::getMPIComm`!"); + THROW_NULL_DEREF; + } } /// Wrap new command diff --git a/tests/testMatrix.cpp b/tests/testMatrix.cpp deleted file mode 100644 index 60a797a5b..000000000 --- a/tests/testMatrix.cpp +++ /dev/null @@ -1,327 +0,0 @@ -// Copyright (c) 2017, Lawrence Livermore National Security, LLC. -// Produced at the Lawrence Livermore National Laboratory (LLNL). -// Written by Cosmin G. Petra, petra1@llnl.gov. -// LLNL-CODE-742473. All rights reserved. -// -// This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp -// is released under the BSD 3-clause license (https://opensource.org/licenses/BSD-3-Clause). -// Please also read “Additional BSD Notice” below. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// i. Redistributions of source code must retain the above copyright notice, this list -// of conditions and the disclaimer below. -// ii. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the disclaimer (as noted below) in the documentation and/or -// other materials provided with the distribution. -// iii. Neither the name of the LLNS/LLNL nor the names of its contributors may be used to -// endorse or promote products derived from this software without specific prior written -// permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY -// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT -// SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Additional BSD Notice -// 1. This notice is required to be provided under our contract with the U.S. Department -// of Energy (DOE). This work was produced at Lawrence Livermore National Laboratory under -// Contract No. DE-AC52-07NA27344 with the DOE. -// 2. Neither the United States Government nor Lawrence Livermore National Security, LLC -// nor any of their employees, makes any warranty, express or implied, or assumes any -// liability or responsibility for the accuracy, completeness, or usefulness of any -// information, apparatus, product, or process disclosed, or represents that its use would -// not infringe privately-owned rights. -// 3. Also, reference herein to any specific commercial products, process, or services by -// trade name, trademark, manufacturer or otherwise does not necessarily constitute or -// imply its endorsement, recommendation, or favoring by the United States Government or -// Lawrence Livermore National Security, LLC. The views and opinions of authors expressed -// herein do not necessarily state or reflect those of the United States Government or -// Lawrence Livermore National Security, LLC, and shall not be used for advertising or -// product endorsement purposes. - -/** - * @file testMatrix.cpp - * - * @author Asher Mancinelli , PNNL - * @author Slaven Peles , PNNL - * - */ -#include -#include - -#include -#include -#include -#include -#include -#include "LinAlg/matrixTestsDense.hpp" - -#ifdef HIOP_USE_RAJA -#include -#include -#include "LinAlg/matrixTestsRajaDense.hpp" -#endif - -int main(int argc, char** argv) -{ - using hiop::tests::global_ordinal_type; - - int rank = 0; - int numRanks = 1; - MPI_Comm comm = MPI_COMM_SELF; - -#ifdef HIOP_USE_MPI - int err; - err = MPI_Init(&argc, &argv); assert(MPI_SUCCESS==err); - comm = MPI_COMM_WORLD; - err = MPI_Comm_rank(comm,&rank); assert(MPI_SUCCESS==err); - err = MPI_Comm_size(comm,&numRanks); assert(MPI_SUCCESS==err); - if(0 == rank && MPI_SUCCESS == err) - printf("Support for MPI is enabled\n"); -#endif - if(rank == 0 && argc > 1) - std::cout << "Executable " << argv[0] << " doesn't take any input."; - - hiop::hiopOptions options; - - global_ordinal_type M_local = 50; - global_ordinal_type K_local = 2 * M_local; - global_ordinal_type N_local = 10 * M_local; - - // all distribution occurs column-wise, so any length - // that will be used as a column of a matrix will have - // to be scaled up by numRanks - global_ordinal_type M_global = M_local * numRanks; - global_ordinal_type K_global = K_local * numRanks; - global_ordinal_type N_global = N_local * numRanks; - - auto n_partition = new global_ordinal_type[numRanks+1]; - auto k_partition = new global_ordinal_type[numRanks+1]; - auto m_partition = new global_ordinal_type[numRanks+1]; - n_partition[0] = 0; - k_partition[0] = 0; - m_partition[0] = 0; - - for(int i = 1; i < numRanks + 1; ++i) - { - n_partition[i] = i*N_local; - k_partition[i] = i*K_local; - m_partition[i] = i*M_local; - } - - int fail = 0; - - // Test dense matrix - { - if (rank==0) - std::cout << "\nTesting hiopMatrixDenseRowMajor ...\n"; - // Matrix dimensions denoted by subscript - // Distributed matrices (only distributed by columns): - hiop::hiopMatrixDenseRowMajor A_kxm(K_local, M_global, m_partition, comm); - hiop::hiopMatrixDenseRowMajor A_kxn(K_local, N_global, n_partition, comm); - hiop::hiopMatrixDenseRowMajor A_mxk(M_local, K_global, k_partition, comm); - hiop::hiopMatrixDenseRowMajor A_mxn(M_local, N_global, n_partition, comm); - hiop::hiopMatrixDenseRowMajor A_nxm(N_local, M_global, m_partition, comm); - // Try factory instead of constructor - hiop::hiopMatrixDense* B_mxn = - hiop::LinearAlgebraFactory::createMatrixDense(M_local, N_global, n_partition, comm); - hiop::hiopMatrixDense* A_mxn_extra_row = - hiop::LinearAlgebraFactory::createMatrixDense(M_local, N_global, n_partition, comm, M_local+1); - - // Non-distributed matrices: - hiop::hiopMatrixDenseRowMajor A_mxk_nodist(M_local, K_local); - // Try factory instead of constructor - hiop::hiopMatrixDense* A_mxm_nodist = - hiop::LinearAlgebraFactory::createMatrixDense(M_local, M_local); - hiop::hiopMatrixDenseRowMajor A_kxn_nodist(K_local, N_local); - hiop::hiopMatrixDenseRowMajor A_kxm_nodist(K_local, M_local); - hiop::hiopMatrixDenseRowMajor A_mxn_nodist(M_local, N_local); - hiop::hiopMatrixDenseRowMajor A_nxn_nodist(N_local, N_local); - - // Vectors with shape of the form: - // x__[non-distributed] - // - // Distributed vectors: - hiop::hiopVectorPar x_n(N_global, n_partition, comm); - - // Non-distributed vectors - hiop::hiopVectorPar x_n_nodist(N_local); - hiop::hiopVectorPar x_m_nodist(M_local); - - hiop::tests::MatrixTestsDense test; - - fail += test.matrixSetToZero(A_mxn, rank); - fail += test.matrixSetToConstant(A_mxn, rank); - fail += test.matrixTimesVec(A_mxn, x_m_nodist, x_n, rank); - fail += test.matrixTransTimesVec(A_mxn, x_m_nodist, x_n, rank); - - if(rank == 0) - { - // These functions are only meant to be called locally - - fail += test.matrixTimesMat(A_mxk_nodist, A_kxn_nodist, A_mxn_nodist); - fail += test.matrixAddDiagonal(A_nxn_nodist, x_n_nodist); - fail += test.matrixAddSubDiagonal(A_nxn_nodist, x_m_nodist); - //fail += test.matrixAddToSymDenseMatrixUpperTriangle(A_nxn_nodist, A_mxk_nodist); - fail += test.matrixTransAddToSymDenseMatrixUpperTriangle(A_nxn_nodist, A_kxm_nodist); - fail += test.matrixAddUpperTriangleToSymDenseMatrixUpperTriangle(A_nxn_nodist, *A_mxm_nodist); -#ifdef HIOP_DEEPCHECKS - fail += test.matrixAssertSymmetry(A_nxn_nodist); - fail += test.matrixOverwriteUpperTriangleWithLower(A_nxn_nodist); - fail += test.matrixOverwriteLowerTriangleWithUpper(A_nxn_nodist); -#endif - // Not part of hiopMatrix interface, specific to matrixTestsDense - fail += test.matrixCopyBlockFromMatrix(*A_mxm_nodist, A_kxn_nodist); - fail += test.matrixCopyFromMatrixBlock(A_kxn_nodist, *A_mxm_nodist); - } - - fail += test.matrixTransTimesMat(A_mxk_nodist, A_kxn, A_mxn, rank); - fail += test.matrixTimesMatTrans(A_mxn, A_mxk_nodist, A_kxn, rank); - fail += test.matrixAddMatrix(A_mxn, *B_mxn, rank); - fail += test.matrixMaxAbsValue(A_mxn, rank); - fail += test.matrixIsFinite(A_mxn, rank); - fail += test.matrixNumRows(A_mxn, M_local, rank); //<-- no row partitioning - fail += test.matrixNumCols(A_mxn, N_global, rank); - - // specific to matrixTestsDense - fail += test.matrixCopyFrom(A_mxn, *B_mxn, rank); - - fail += test.matrixAppendRow(*A_mxn_extra_row, x_n, rank); - fail += test.matrixCopyRowsFrom(A_kxn, A_mxn, rank); - fail += test.matrixCopyRowsFromSelect(A_mxn, A_kxn, rank); - fail += test.matrixShiftRows(A_mxn, rank); - fail += test.matrixReplaceRow(A_mxn, x_n, rank); - fail += test.matrixGetRow(A_mxn, x_n, rank); - - // Delete test objects - delete B_mxn; - delete A_mxm_nodist; - delete A_mxn_extra_row; - } - - // Test RAJA dense matrix -#ifdef HIOP_USE_RAJA - { - if (rank==0) - std::cout << "\nTesting hiopMatrixRajaDense ...\n"; - - options.SetStringValue("mem_space", "device"); - hiop::LinearAlgebraFactory::set_mem_space(options.GetString("mem_space")); - std::string mem_space = hiop::LinearAlgebraFactory::get_mem_space(); - - // Matrix dimensions denoted by subscript - // Distributed matrices (only distributed by columns): - hiop::hiopMatrixRajaDense A_kxm(K_local, M_global, mem_space, m_partition, comm); - hiop::hiopMatrixRajaDense A_kxn(K_local, N_global, mem_space, n_partition, comm); - hiop::hiopMatrixRajaDense A_mxk(M_local, K_global, mem_space, k_partition, comm); - hiop::hiopMatrixRajaDense A_mxn(M_local, N_global, mem_space, n_partition, comm); - hiop::hiopMatrixRajaDense A_nxm(N_local, M_global, mem_space, m_partition, comm); - // Try factory instead of constructor - hiop::hiopMatrixDense* B_mxn = - hiop::LinearAlgebraFactory::createMatrixDense(M_local, N_global, n_partition, comm); - hiop::hiopMatrixDense* A_mxn_extra_row = - hiop::LinearAlgebraFactory::createMatrixDense(M_local, N_global, n_partition, comm, M_local+1); - - // Non-distributed matrices: - hiop::hiopMatrixRajaDense A_mxk_nodist(M_local, K_local, mem_space); - // Try factory instead of constructor - hiop::hiopMatrixDense* A_mxm_nodist = - hiop::LinearAlgebraFactory::createMatrixDense(M_local, M_local); - hiop::hiopMatrixRajaDense A_kxn_nodist(K_local, N_local, mem_space); - hiop::hiopMatrixRajaDense A_kxm_nodist(K_local, M_local, mem_space); - hiop::hiopMatrixRajaDense A_mxn_nodist(M_local, N_local, mem_space); - hiop::hiopMatrixRajaDense A_nxn_nodist(N_local, N_local, mem_space); - - // Vectors with shape of the form: - // x__[non-distributed] - // - // Distributed vectors: - hiop::hiopVectorRajaPar x_n(N_global, mem_space, n_partition, comm); - - // Non-distributed vectors - hiop::hiopVectorRajaPar x_n_nodist(N_local, mem_space); - hiop::hiopVectorRajaPar x_m_nodist(M_local, mem_space); - - hiop::tests::MatrixTestsRajaDense test; - - fail += test.matrixSetToZero(A_mxn, rank); - fail += test.matrixSetToConstant(A_mxn, rank); - fail += test.matrixTimesVec(A_mxn, x_m_nodist, x_n, rank); - fail += test.matrixTransTimesVec(A_mxn, x_m_nodist, x_n, rank); - - if(rank == 0) - { - // These methods are local - fail += test.matrixTimesMat(A_mxk_nodist, A_kxn_nodist, A_mxn_nodist); - fail += test.matrixAddDiagonal(A_nxn_nodist, x_n_nodist); - fail += test.matrixAddSubDiagonal(A_nxn_nodist, x_m_nodist); - //fail += test.matrixAddToSymDenseMatrixUpperTriangle(A_nxn_nodist, A_mxk_nodist); - fail += test.matrixTransAddToSymDenseMatrixUpperTriangle(A_nxn_nodist, A_kxm_nodist); - fail += test.matrixAddUpperTriangleToSymDenseMatrixUpperTriangle(A_nxn_nodist, *A_mxm_nodist); -#ifdef HIOP_DEEPCHECKS - fail += test.matrixAssertSymmetry(A_nxn_nodist); - fail += test.matrixOverwriteUpperTriangleWithLower(A_nxn_nodist); - fail += test.matrixOverwriteLowerTriangleWithUpper(A_nxn_nodist); -#endif - // Not part of hiopMatrix interface, specific to matrixTestsDense - fail += test.matrixCopyBlockFromMatrix(*A_mxm_nodist, A_kxn_nodist); - fail += test.matrixCopyFromMatrixBlock(A_kxn_nodist, *A_mxm_nodist); - } - - fail += test.matrixTransTimesMat(A_mxk_nodist, A_kxn, A_mxn, rank); - fail += test.matrixTimesMatTrans(A_mxn, A_mxk_nodist, A_kxn, rank); - fail += test.matrixAddMatrix(A_mxn, *B_mxn, rank); - fail += test.matrixMaxAbsValue(A_mxn, rank); - fail += test.matrixIsFinite(A_mxn, rank); - fail += test.matrixNumRows(A_mxn, M_local, rank); //<- no row partitioning - fail += test.matrixNumCols(A_mxn, N_global, rank); - - // specific to matrixTestsDense - fail += test.matrixCopyFrom(A_mxn, *B_mxn, rank); - - fail += test.matrixAppendRow(*A_mxn_extra_row, x_n, rank); - fail += test.matrixCopyRowsFrom(A_kxn, A_mxn, rank); - fail += test.matrixCopyRowsFromSelect(A_mxn, A_kxn, rank); - fail += test.matrixShiftRows(A_mxn, rank); - fail += test.matrixReplaceRow(A_mxn, x_n, rank); - fail += test.matrixGetRow(A_mxn, x_n, rank); - - // Delete test objects - delete B_mxn; - delete A_mxm_nodist; - delete A_mxn_extra_row; - - // Set memory space back to default value - options.SetStringValue("mem_space", "default"); - } -#endif - - if (rank == 0) - { - if(fail) - { - std::cout << "\n" << fail << " dense matrix tests failed\n\n"; - } - else - { - std::cout << "\nAll dense matrix tests passed\n\n"; - } - } - - delete[] m_partition; - delete[] n_partition; - delete[] k_partition; - -#ifdef HIOP_USE_MPI - MPI_Finalize(); -#endif - - return fail; -} diff --git a/tests/testMatrixDense.cpp b/tests/testMatrixDense.cpp new file mode 100644 index 000000000..03ac15e60 --- /dev/null +++ b/tests/testMatrixDense.cpp @@ -0,0 +1,284 @@ +// Copyright (c) 2017, Lawrence Livermore National Security, LLC. +// Produced at the Lawrence Livermore National Laboratory (LLNL). +// Written by Cosmin G. Petra, petra1@llnl.gov. +// LLNL-CODE-742473. All rights reserved. +// +// This file is part of HiOp. For details, see https://github.com/LLNL/hiop. HiOp +// is released under the BSD 3-clause license (https://opensource.org/licenses/BSD-3-Clause). +// Please also read “Additional BSD Notice” below. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// i. Redistributions of source code must retain the above copyright notice, this list +// of conditions and the disclaimer below. +// ii. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the disclaimer (as noted below) in the documentation and/or +// other materials provided with the distribution. +// iii. Neither the name of the LLNS/LLNL nor the names of its contributors may be used to +// endorse or promote products derived from this software without specific prior written +// permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +// SHALL LAWRENCE LIVERMORE NATIONAL SECURITY, LLC, THE U.S. DEPARTMENT OF ENERGY OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Additional BSD Notice +// 1. This notice is required to be provided under our contract with the U.S. Department +// of Energy (DOE). This work was produced at Lawrence Livermore National Laboratory under +// Contract No. DE-AC52-07NA27344 with the DOE. +// 2. Neither the United States Government nor Lawrence Livermore National Security, LLC +// nor any of their employees, makes any warranty, express or implied, or assumes any +// liability or responsibility for the accuracy, completeness, or usefulness of any +// information, apparatus, product, or process disclosed, or represents that its use would +// not infringe privately-owned rights. +// 3. Also, reference herein to any specific commercial products, process, or services by +// trade name, trademark, manufacturer or otherwise does not necessarily constitute or +// imply its endorsement, recommendation, or favoring by the United States Government or +// Lawrence Livermore National Security, LLC. The views and opinions of authors expressed +// herein do not necessarily state or reflect those of the United States Government or +// Lawrence Livermore National Security, LLC, and shall not be used for advertising or +// product endorsement purposes. + +/** + * @file testMatrixDense.cpp + * + * @author Asher Mancinelli , PNNL + * @author Slaven Peles , PNNL + * @author Robert Rutherford , PNNL + * + */ +#include +#include + +#include +#include +#include +#include +#include +#include "LinAlg/matrixTestsDenseRowMajor.hpp" + +#ifdef HIOP_USE_RAJA +#include +#include +#include "LinAlg/matrixTestsRajaDense.hpp" +#endif + +template +static int runTests(const char* mem_space, MPI_Comm comm); + +int main(int argc, char** argv) +{ + using namespace hiop::tests; + using hiop::tests::global_ordinal_type; + + int rank = 0; + MPI_Comm comm = MPI_COMM_SELF; + +#ifdef HIOP_USE_MPI + int err; + err = MPI_Init(&argc, &argv); assert(MPI_SUCCESS==err); + comm = MPI_COMM_WORLD; + err = MPI_Comm_rank(comm,&rank); assert(MPI_SUCCESS==err); + if(0 == rank && MPI_SUCCESS == err) + std::cout << "\nRunning MPI enabled tests ...\n"; +#endif + if(rank == 0 && argc > 1) + std::cout << "Executable " << argv[0] << " doesn't take any input."; + + int fail = 0; + + // + // Test HiOp Dense Matrices + // + if (rank == 0) + std::cout << "\nTesting HiOp default dense matrix implementation:\n"; + fail += runTests("default", comm); +#ifdef HIOP_USE_RAJA +#ifdef HIOP_USE_GPU + if (rank == 0) + { + std::cout << "\nTesting HiOp RAJA dense matrix implementation ...\n"; + std::cout << " ... using device memory space:\n"; + } + fail += runTests("device", comm); + if (rank == 0) + { + std::cout << "\nTesting HiOp RAJA dense matrix implementation ...\n"; + std::cout << " ... using unified virtual memory space:\n"; + } + fail += runTests("um", comm); +#else + if (rank == 0) + { + std::cout << "\nTesting HiOp RAJA dense matrix implementation ...\n"; + std::cout << " ... using unified host memory space:\n"; + } + fail += runTests("host", comm); +#endif // GPU +#endif // RAJA + + if (rank == 0) + { + if(fail) + { + std::cout << "\n" << fail << " dense matrix tests failed\n\n"; + } + else + { + std::cout << "\nAll dense matrix tests passed\n\n"; + } + } + +#ifdef HIOP_USE_MPI + MPI_Finalize(); +#endif + + return fail; +} + +/// Driver for all dense matrix tests +template +static int runTests(const char* mem_space, MPI_Comm comm) +{ + using namespace hiop; + using hiop::tests::global_ordinal_type; + + int rank=0; + int numRanks=1; + +#ifdef HIOP_USE_MPI + MPI_Comm_rank(comm, &rank); + MPI_Comm_size(comm, &numRanks); +#endif + + T test; + + hiopOptions options; + options.SetStringValue("mem_space", mem_space); + LinearAlgebraFactory::set_mem_space(mem_space); + + int fail = 0; + + global_ordinal_type M_local = 50; + global_ordinal_type K_local = 2 * M_local; + global_ordinal_type N_local = 10 * M_local; + + // all distribution occurs column-wise, so any length + // that will be used as a column of a matrix will have + // to be scaled up by numRanks + global_ordinal_type M_global = M_local * numRanks; + global_ordinal_type K_global = K_local * numRanks; + global_ordinal_type N_global = N_local * numRanks; + + auto n_partition = new global_ordinal_type[numRanks+1]; + auto k_partition = new global_ordinal_type[numRanks+1]; + auto m_partition = new global_ordinal_type[numRanks+1]; + n_partition[0] = 0; + k_partition[0] = 0; + m_partition[0] = 0; + + for(int i = 1; i < numRanks + 1; ++i) + { + n_partition[i] = i*N_local; + k_partition[i] = i*K_local; + m_partition[i] = i*M_local; + } + + // Distributed matrices: + hiopMatrixDense* A_kxm = LinearAlgebraFactory::createMatrixDense(K_local, M_global, m_partition, comm); + hiopMatrixDense* A_kxn = LinearAlgebraFactory::createMatrixDense(K_local, N_global, n_partition, comm); + hiopMatrixDense* A_mxk = LinearAlgebraFactory::createMatrixDense(M_local, K_global, k_partition, comm); + hiopMatrixDense* A_mxn = LinearAlgebraFactory::createMatrixDense(M_local, N_global, n_partition, comm); + hiopMatrixDense* A_nxm = LinearAlgebraFactory::createMatrixDense(N_local, M_global, m_partition, comm); + hiopMatrixDense* B_mxn = LinearAlgebraFactory::createMatrixDense(M_local, N_global, n_partition, comm); + hiopMatrixDense* A_mxn_extra_row = LinearAlgebraFactory::createMatrixDense(M_local, N_global, n_partition, comm, M_local+1); + + // Non-distributed matrices: + hiopMatrixDense* A_mxk_nodist = LinearAlgebraFactory::createMatrixDense(M_local, K_local); + hiopMatrixDense* A_mxm_nodist = LinearAlgebraFactory::createMatrixDense(M_local, M_local); + hiopMatrixDense* A_kxn_nodist = LinearAlgebraFactory::createMatrixDense(K_local, N_local); + hiopMatrixDense* A_kxm_nodist = LinearAlgebraFactory::createMatrixDense(K_local, M_local); + hiopMatrixDense* A_mxn_nodist = LinearAlgebraFactory::createMatrixDense(M_local, N_local); + hiopMatrixDense* A_nxn_nodist = LinearAlgebraFactory::createMatrixDense(N_local, N_local); + + // Vectors with shape of the form: + // x__[non-distributed] + // + // Distributed vectors: + hiopVector* x_n = LinearAlgebraFactory::createVector(N_global, n_partition, comm); + + // Non-distributed vectors + hiopVector* x_n_nodist = LinearAlgebraFactory::createVector(N_local); + hiopVector* x_m_nodist = LinearAlgebraFactory::createVector(M_local); + + + fail += test.matrixSetToZero(*A_mxn, rank); + fail += test.matrixSetToConstant(*A_mxn, rank); + fail += test.matrixTimesVec(*A_mxn, *x_m_nodist, *x_n, rank); + fail += test.matrixTransTimesVec(*A_mxn, *x_m_nodist, *x_n, rank); + + if(rank == 0) + { + // These methods are local + fail += test.matrixTimesMat(*A_mxk_nodist, *A_kxn_nodist, *A_mxn_nodist); + fail += test.matrixAddDiagonal(*A_nxn_nodist, *x_n_nodist); + fail += test.matrixAddSubDiagonal(*A_nxn_nodist, *x_m_nodist); + fail += test.matrixTransAddToSymDenseMatrixUpperTriangle(*A_nxn_nodist, *A_kxm_nodist); + fail += test.matrixAddUpperTriangleToSymDenseMatrixUpperTriangle(*A_nxn_nodist, *A_mxm_nodist); +#ifdef HIOP_DEEPCHECKS + fail += test.matrixAssertSymmetry(*A_nxn_nodist); + fail += test.matrixOverwriteUpperTriangleWithLower(*A_nxn_nodist); + fail += test.matrixOverwriteLowerTriangleWithUpper(*A_nxn_nodist); +#endif + // Not part of hiopMatrix interface, specific to matrixTestsDenseRowMajor + fail += test.matrixCopyBlockFromMatrix(*A_mxm_nodist, *A_kxn_nodist); + fail += test.matrixCopyFromMatrixBlock(*A_kxn_nodist, *A_mxm_nodist); + } + + fail += test.matrixTransTimesMat(*A_mxk_nodist, *A_kxn, *A_mxn, rank); + fail += test.matrixTimesMatTrans(*A_mxn, *A_mxk_nodist, *A_kxn, rank); + fail += test.matrixAddMatrix(*A_mxn, *B_mxn, rank); + fail += test.matrixMaxAbsValue(*A_mxn, rank); + fail += test.matrixIsFinite(*A_mxn, rank); + fail += test.matrixNumRows(*A_mxn, M_local, rank); //<- no row partitioning + fail += test.matrixNumCols(*A_mxn, N_global, rank); + + // specific to matrixTestsDenseRowMajor + fail += test.matrixCopyFrom(*A_mxn, *B_mxn, rank); + + fail += test.matrixAppendRow(*A_mxn_extra_row, *x_n, rank); + fail += test.matrixCopyRowsFrom(*A_kxn, *A_mxn, rank); + fail += test.matrixCopyRowsFromSelect(*A_mxn, *A_kxn, rank); + fail += test.matrixShiftRows(*A_mxn, rank); + fail += test.matrixReplaceRow(*A_mxn, *x_n, rank); + fail += test.matrixGetRow(*A_mxn, *x_n, rank); + + delete A_kxm; + delete A_kxn; + delete A_mxk; + delete A_mxn; + delete A_nxm; + delete B_mxn; + delete A_mxn_extra_row; + delete A_mxk_nodist; + delete A_mxm_nodist; + delete A_kxn_nodist; + delete A_kxm_nodist; + delete A_mxn_nodist; + delete A_nxn_nodist; + delete x_n; + delete x_n_nodist; + delete x_m_nodist; + delete[] m_partition; + delete[] n_partition; + delete[] k_partition; + + return fail; +}