void MatrixMxN<Scalar>::singularValueDecomposition(MatrixMxN<Scalar> &left_singular_vectors, VectorND<Scalar> &singular_values, MatrixMxN<Scalar> &right_singular_vectors) const { #ifdef PHYSIKA_USE_EIGEN_MATRIX //hack: Eigen::SVD does not support integer types, hence we cast Scalar to long double for decomposition unsigned int rows = this->rows(), cols = this->cols(); Eigen::Matrix<long double,Eigen::Dynamic,Eigen::Dynamic> temp_matrix(rows,cols); for(unsigned int i = 0; i < rows; ++i) for(unsigned int j = 0; j < cols; ++j) temp_matrix(i,j) = static_cast<long double>((*ptr_eigen_matrix_MxN_)(i,j)); Eigen::JacobiSVD<Eigen::Matrix<long double,Eigen::Dynamic,Eigen::Dynamic> > svd(temp_matrix,Eigen::ComputeThinU|Eigen::ComputeThinV); const Eigen::Matrix<long double,Eigen::Dynamic,Eigen::Dynamic> &left = svd.matrixU(), &right = svd.matrixV(); const Eigen::Matrix<long double,Eigen::Dynamic,1> &values = svd.singularValues(); //resize if have to if(left_singular_vectors.rows() != left.rows() || left_singular_vectors.cols() != left.cols()) left_singular_vectors.resize(left.rows(),left.cols()); if(right_singular_vectors.rows() != right.rows() || right_singular_vectors.cols() != right.cols()) right_singular_vectors.resize(right.rows(),right.cols()); if(singular_values.dims() != values.rows()) singular_values.resize(values.rows()); //copy the result for(unsigned int i = 0; i < left.rows(); ++i) for(unsigned int j = 0; j < left.cols(); ++j) left_singular_vectors(i,j) = static_cast<Scalar>(left(i,j)); for(unsigned int i = 0; i < right.rows(); ++i) for(unsigned int j = 0; j < right.cols(); ++j) right_singular_vectors(i,j) = static_cast<Scalar>(right(i,j)); for(unsigned int i = 0; i < values.rows(); ++i) singular_values[i] = static_cast<Scalar>(values(i,0)); #elif defined(PHYSIKA_USE_BUILT_IN_MATRIX) std::cerr<<"SVD not implemeted for built in matrix!\n"; std::exit(EXIT_FAILURE); #endif }
void SetUp(const ::benchmark::State& state) { std::mt19937 rng{0}; std::uniform_real_distribution<> d(0.0, 1.0); const auto n = static_cast<size_t>(state.range(0)); mat.resize(n, n); x.resize(n); y.resize(n); mat.forEachIndex([&](size_t i, size_t j) { mat(i, j) = d(rng); }); x.forEachIndex([&](size_t i) { x[i] = d(rng); y[i] = d(rng); }); }
void FdmJacobiSolver3::relax(const MatrixCsrD& A, const VectorND& b, VectorND* x_, VectorND* xTemp_) { const auto rp = A.rowPointersBegin(); const auto ci = A.columnIndicesBegin(); const auto nnz = A.nonZeroBegin(); VectorND& x = *x_; VectorND& xTemp = *xTemp_; b.parallelForEachIndex([&](size_t i) { const size_t rowBegin = rp[i]; const size_t rowEnd = rp[i + 1]; double r = 0.0; double diag = 1.0; for (size_t jj = rowBegin; jj < rowEnd; ++jj) { size_t j = ci[jj]; if (i == j) { diag = nnz[jj]; } else { r += nnz[jj] * x[j]; } } xTemp[i] = (b[i] - r) / diag; }); }
void FdmGaussSeidelSolver3::relax(const MatrixCsrD& A, const VectorND& b, double sorFactor, VectorND* x_) { const auto rp = A.rowPointersBegin(); const auto ci = A.columnIndicesBegin(); const auto nnz = A.nonZeroBegin(); VectorND& x = *x_; b.forEachIndex([&](size_t i) { const size_t rowBegin = rp[i]; const size_t rowEnd = rp[i + 1]; double r = 0.0; double diag = 1.0; for (size_t jj = rowBegin; jj < rowEnd; ++jj) { size_t j = ci[jj]; if (i == j) { diag = nnz[jj]; } else { r += nnz[jj] * x[j]; } } x[i] = (1.0 - sorFactor) * x[i] + sorFactor * (b[i] - r) / diag; }); }
const MatrixMxN<Scalar> VectorND<Scalar>::outerProduct(const VectorND<Scalar> &vec2) const { MatrixMxN<Scalar> result(this->dims(),vec2.dims()); for(unsigned int i = 0; i < result.rows(); ++i) for(unsigned int j = 0; j < result.cols(); ++j) result(i,j) = (*this)[i]*vec2[j]; return result; }
void MatrixMxN<Scalar>::eigenDecomposition(VectorND<Scalar> &eigen_values_real, VectorND<Scalar> &eigen_values_imag, MatrixMxN<Scalar> &eigen_vectors_real, MatrixMxN<Scalar> &eigen_vectors_imag) { unsigned int rows = this->rows(), cols = this->cols(); if(rows != cols) { std::cerr<<"Eigen decomposition is only valid for square matrix!\n"; std::exit(EXIT_FAILURE); } #ifdef PHYSIKA_USE_EIGEN_MATRIX //hack: Eigen::EigenSolver does not support integer types, hence we cast Scalar to long double for decomposition Eigen::Matrix<long double,Eigen::Dynamic,Eigen::Dynamic> temp_matrix(rows,cols); for(unsigned int i = 0; i < rows; ++i) for(unsigned int j = 0; j < cols; ++j) temp_matrix(i,j) = static_cast<long double>((*ptr_eigen_matrix_MxN_)(i,j)); Eigen::EigenSolver<Eigen::Matrix<long double,Eigen::Dynamic,Eigen::Dynamic> > eigen(temp_matrix); Eigen::Matrix<std::complex<long double>,Eigen::Dynamic,Eigen::Dynamic> vectors = eigen.eigenvectors(); const Eigen::Matrix<std::complex<long double>,Eigen::Dynamic,1> &values = eigen.eigenvalues(); //resize if have to if(eigen_vectors_real.rows() != vectors.rows() || eigen_vectors_real.cols() != vectors.cols()) eigen_vectors_real.resize(vectors.rows(),vectors.cols()); if(eigen_vectors_imag.rows() != vectors.rows() || eigen_vectors_imag.cols() != vectors.cols()) eigen_vectors_imag.resize(vectors.rows(),vectors.cols()); if(eigen_values_real.dims() != values.rows()) eigen_values_real.resize(values.rows()); if(eigen_values_imag.dims() != values.rows()) eigen_values_imag.resize(values.rows()); //copy the result for(unsigned int i = 0; i < vectors.rows(); ++i) for(unsigned int j = 0; j < vectors.cols(); ++j) { eigen_vectors_real(i,j) = static_cast<Scalar>(vectors(i,j).real()); eigen_vectors_imag(i,j) = static_cast<Scalar>(vectors(i,j).imag()); } for(unsigned int i = 0; i < values.rows(); ++i) { eigen_values_real[i] = static_cast<Scalar>(values(i,0).real()); eigen_values_imag[i] = static_cast<Scalar>(values(i,0).imag()); } #elif defined(PHYSIKA_USE_BUILT_IN_MATRIX) std::cerr<<"Eigen decomposition not implemeted for built in matrix!\n"; std::exit(EXIT_FAILURE); #endif }
VectorND<Scalar>::VectorND(const VectorND<Scalar> &vec2) #ifdef PHYSIKA_USE_EIGEN_VECTOR :eigen_vector_Nx_(vec2.eigen_vector_Nx_) #endif { #ifdef PHYSIKA_USE_BUILT_IN_VECTOR allocMemory(vec2.dims()); *this = vec2; #endif }
Scalar VectorND<Scalar>::dot(const VectorND<Scalar> &vec2) const { unsigned int dim1 = (*this).dims(); unsigned int dim2 = vec2.dims(); if(dim1 != dim2) throw PhysikaException("vector dimension mismatch!"); Scalar result = static_cast<Scalar>(0.0); for(unsigned int i = 0; i < dim1; ++i) result += (*this)[i]*vec2[i]; return result; }
void FdmIccgSolver2::PreconditionerCompressed::solve(const VectorND& b, VectorND* x) { const ssize_t size = static_cast<ssize_t>(b.size()); const auto rp = A->rowPointersBegin(); const auto ci = A->columnIndicesBegin(); const auto nnz = A->nonZeroBegin(); b.forEachIndex([&](size_t i) { const size_t rowBegin = rp[i]; const size_t rowEnd = rp[i + 1]; double sum = b[i]; for (size_t jj = rowBegin; jj < rowEnd; ++jj) { size_t j = ci[jj]; if (j < i) { sum -= nnz[jj] * y[j]; } } y[i] = sum * d[i]; }); for (ssize_t i = size - 1; i >= 0; --i) { const size_t rowBegin = rp[i]; const size_t rowEnd = rp[i + 1]; double sum = y[i]; for (size_t jj = rowBegin; jj < rowEnd; ++jj) { ssize_t j = static_cast<ssize_t>(ci[jj]); if (j > i) { sum -= nnz[jj] * (*x)[j]; } } (*x)[i] = sum * d[i]; } }
VectorND<Scalar> MatrixMxN<Scalar>::operator* (const VectorND<Scalar> &vec) const { unsigned int mat_row = (*this).rows(); unsigned int mat_col = (*this).cols(); unsigned int vec_dim = vec.dims(); if(mat_col!=vec_dim) { std::cerr<<"Matrix*Vector: Matrix and vector sizes do not match!\n"; std::exit(EXIT_FAILURE); } VectorND<Scalar> result(mat_row,0.0); for(unsigned int i = 0; i < mat_row; ++i) { for(unsigned int j = 0; j < mat_col; ++j) result[i] += (*this)(i,j)*vec[j]; } return result; }
bool VectorND<Scalar>::operator== (const VectorND<Scalar> &vec2) const { unsigned int dim1 = (*this).dims(); unsigned int dim2 = vec2.dims(); if(dim1 != dim2) return false; for(unsigned int i = 0; i < dim1; ++i) { if(is_floating_point<Scalar>::value) { if(isEqual((*this)[i],vec2[i])==false) return false; } else { if((*this)[i] != vec2[i]) return false; } } return true; }
TEST(MatrixCsr, OperatorOverloadings) { const MatrixCsrD matA = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}}; const MatrixCsrD addResult1 = matA + 3.5; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(i + 4.5, addResult1.nonZero(i)); } const MatrixCsrD matC = {{3.0, -1.0, 2.0}, {9.0, 2.0, 8.0}}; const MatrixCsrD addResult2 = matA + matC; const MatrixCsrD addAns1 = {{4.0, 1.0, 5.0}, {13.0, 7.0, 14.0}}; EXPECT_TRUE(addAns1.isEqual(addResult2)); const MatrixCsrD matD = {{3.0, 0.0, 2.0}, {0.0, 2.0, 0.0}}; const MatrixCsrD addResult3 = matA + matD; const MatrixCsrD addAns2 = {{4.0, 2.0, 5.0}, {4.0, 7.0, 6.0}}; EXPECT_TRUE(addAns2.isEqual(addResult3)); const MatrixCsrD matE = {{3.0, 0.0, 2.0}, {0.0, 0.0, 0.0}}; const MatrixCsrD addResult4 = matA + matE; const MatrixCsrD addAns3 = {{4.0, 2.0, 5.0}, {4.0, 5.0, 6.0}}; EXPECT_TRUE(addAns3.isEqual(addResult4)); const MatrixCsrD subResult1 = matA - 1.5; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(i - 0.5, subResult1.nonZero(i)); } const MatrixCsrD subResult2 = matA - matC; const MatrixCsrD ans2 = {{-2.0, 3.0, 1.0}, {-5.0, 3.0, -2.0}}; EXPECT_TRUE(ans2.isSimilar(subResult2)); const MatrixCsrD matB = matA * 2.0; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(2.0 * (i + 1.0), matB.nonZero(i)); } const VectorND vecA = {-1.0, 9.0, 8.0}; const VectorND vecB = matA * vecA; const VectorND ansV = {41.0, 89.0}; EXPECT_TRUE(ansV.isEqual(vecB)); const MatrixCsrD matF = {{3.0, -1.0}, {2.0, 9.0}, {2.0, 8.0}}; const MatrixCsrD matG = matA * matF; const MatrixCsrD ans3 = {{13.0, 41.0}, {34.0, 89.0}}; EXPECT_TRUE(ans3.isEqual(matG)); const MatrixCsrD matH = matA / 2.0; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ((i + 1.0) / 2.0, matH.nonZero(i)); } const MatrixCsrD matI = 3.5 + matA; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(i + 4.5, matI.nonZero(i)); } const MatrixCsrD matJ = 1.5 - matA; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(0.5 - i, matJ.nonZero(i)); } const MatrixCsrD matM = 2.0 * matA; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(2.0 * (i + 1.0), matM.nonZero(i)); } const MatrixCsrD matP = 2.0 / matA; for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(2.0 / (i + 1.0), matP.nonZero(i)); } }
TEST(MatrixCsr, BinaryOperatorMethods) { const MatrixCsrD matA = {{1.0, 2.0, 3.0}, {4.0, 5.0, 6.0}}; const MatrixCsrD addResult1 = matA.add(3.5); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(i + 4.5, addResult1.nonZero(i)); } const MatrixCsrD matC = {{3.0, -1.0, 2.0}, {9.0, 2.0, 8.0}}; const MatrixCsrD addResult2 = matA.add(matC); const MatrixCsrD addAns1 = {{4.0, 1.0, 5.0}, {13.0, 7.0, 14.0}}; EXPECT_TRUE(addAns1.isEqual(addResult2)); const MatrixCsrD matD = {{3.0, 0.0, 2.0}, {0.0, 2.0, 0.0}}; const MatrixCsrD addResult3 = matA.add(matD); const MatrixCsrD addAns2 = {{4.0, 2.0, 5.0}, {4.0, 7.0, 6.0}}; EXPECT_TRUE(addAns2.isEqual(addResult3)); const MatrixCsrD matE = {{3.0, 0.0, 2.0}, {0.0, 0.0, 0.0}}; const MatrixCsrD addResult4 = matA.add(matE); const MatrixCsrD addAns3 = {{4.0, 2.0, 5.0}, {4.0, 5.0, 6.0}}; EXPECT_TRUE(addAns3.isEqual(addResult4)); const MatrixCsrD subResult1 = matA.sub(1.5); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(i - 0.5, subResult1.nonZero(i)); } const MatrixCsrD subResult2 = matA.sub(matC); const MatrixCsrD ans2 = {{-2.0, 3.0, 1.0}, {-5.0, 3.0, -2.0}}; EXPECT_TRUE(ans2.isSimilar(subResult2)); const MatrixCsrD matB = matA.mul(2.0); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(2.0 * (i + 1.0), matB.nonZero(i)); } const VectorND vecA = {-1.0, 9.0, 8.0}; const VectorND vecB = matA.mul(vecA); const VectorND ansV = {41.0, 89.0}; EXPECT_TRUE(ansV.isEqual(vecB)); const MatrixCsrD matF = {{3.0, -1.0}, {2.0, 9.0}, {2.0, 8.0}}; const MatrixCsrD matG = matA.mul(matF); const MatrixCsrD ans3 = {{13.0, 41.0}, {34.0, 89.0}}; EXPECT_TRUE(ans3.isEqual(matG)); const MatrixCsrD matH = matA.div(2.0); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ((i + 1.0) / 2.0, matH.nonZero(i)); } const MatrixCsrD matI = matA.radd(3.5); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(i + 4.5, matI.nonZero(i)); } const MatrixCsrD matJ = matA.rsub(1.5); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(0.5 - i, matJ.nonZero(i)); } const MatrixCsrD matK = {{3.0, -1.0, 2.0}, {9.0, 2.0, 8.0}}; const MatrixCsrD matL = matA.rsub(matK); const MatrixCsrD ans4 = {{2.0, -3.0, -1.0}, {5.0, -3.0, 2.0}}; EXPECT_EQ(ans4, matL); const MatrixCsrD matM = matA.rmul(2.0); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(2.0 * (i + 1.0), matM.nonZero(i)); } const MatrixCsrD matP = matA.rdiv(2.0); for (size_t i = 0; i < 6; ++i) { EXPECT_EQ(2.0 / (i + 1.0), matP.nonZero(i)); } }