From 80d6f85a18e8d35250a67340ecc414b62267391e Mon Sep 17 00:00:00 2001 From: Stergios Terpinas Date: Thu, 15 Jun 2023 13:01:57 +0300 Subject: [PATCH] Replace Armadillo with Eigen. --- BUILD | 2 +- WORKSPACE | 19 ++-- src/amatrix.cc | 230 ++++++++++++++++++++++++------------------ src/include/amatrix.h | 19 ++-- 4 files changed, 152 insertions(+), 118 deletions(-) diff --git a/BUILD b/BUILD index 4b1f358..76d660e 100644 --- a/BUILD +++ b/BUILD @@ -129,7 +129,7 @@ cc_library( ":similarity_to_quality_mapper", ":tflite_quality_mapper", ":visqol_config_cc_proto", - "@armadillo_headers//:armadillo_header", + "@eigen//:eigen", "@com_google_absl//absl/flags:flag", "@com_google_absl//absl/flags:parse", "@com_google_absl//absl/flags:usage", diff --git a/WORKSPACE b/WORKSPACE index f3c5aeb..7e0019c 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -158,20 +158,21 @@ cc_library( urls = ["https://github.com/cjlin1/libsvm/archive/v324.zip"], ) -# Armadillo Headers +# Eigen dependency http_archive( - name = "armadillo_headers", + name = "eigen", build_file_content = """ cc_library( - name = "armadillo_header", - hdrs = glob(["include/armadillo", "include/armadillo_bits/*.hpp"]), - includes = ["include/"], - visibility = ["//visibility:public"], + name = 'eigen', + srcs = [], + includes = ['Eigen'], + hdrs = glob(['Eigen/**']), + visibility = ['//visibility:public'], ) """, - sha256 = "53d7ad6124d06fdede8d839c091c649c794dae204666f1be0d30d7931737d635", - strip_prefix = "armadillo-9.900.1", - urls = ["http://sourceforge.net/projects/arma/files/armadillo-9.900.1.tar.xz"], + sha256 = "0fa5cafe78f66d2b501b43016858070d52ba47bd9b1016b0165a7b8e04675677", + strip_prefix = "eigen-3.3.9", + urls = ["https://gitlab.com/libeigen/eigen/-/archive/3.3.9/eigen-3.3.9.tar.bz2",], ) # PFFFT diff --git a/src/amatrix.cc b/src/amatrix.cc index 5697821..83a25fb 100644 --- a/src/amatrix.cc +++ b/src/amatrix.cc @@ -14,8 +14,8 @@ #include "amatrix.h" -#include #include +#include #include #include #include @@ -25,95 +25,97 @@ namespace Visqol { template inline AMatrix::AMatrix(const AMatrix& other) { - matrix_ = arma::Mat(other.matrix_); + matrix_ = BackendMatrix(other.matrix_); } template -inline AMatrix::AMatrix(const arma::Mat& mat) { +inline AMatrix::AMatrix(const BackendMatrix& mat) { matrix_ = mat; } template inline AMatrix::AMatrix(const std::vector& col) { - matrix_ = arma::Mat(col); + matrix_ = BackendMatrix::Map(col.data(), col.size(), 1); } template inline AMatrix::AMatrix(const absl::Span& col) { - matrix_ = arma::Mat(col.data(), col.size(), 1); + matrix_ = BackendMatrix::Map(col.data(), col.size(), 1); } template inline AMatrix::AMatrix(const std::valarray& va) { std::vector v; - v.reserve(va.size()); + v.resize(va.size()); v.assign(std::begin(va), std::end(va)); - matrix_ = arma::Mat(v); + matrix_ = BackendMatrix::Map(v.data(), v.size(), 1); } template inline AMatrix::AMatrix(const std::vector>& vecOfCols) { // assumes all vectors all of equal length - matrix_ = arma::Mat(vecOfCols[0].size(), vecOfCols.size()); + matrix_ = BackendMatrix(vecOfCols[0].size(), vecOfCols.size()); for (size_t i = 0; i < vecOfCols.size(); i++) { - matrix_.col(i) = arma::Col(vecOfCols[i]); + matrix_.col(i) = BackendMatrix::Map(vecOfCols[i].data(), vecOfCols[i].size(), 1); } } template inline AMatrix::AMatrix(size_t rows, size_t cols, std::vector&& data) { - matrix_ = arma::Mat(&data[0], (arma::uword)rows, (arma::uword)cols, false); + // TODO: We should avoid copying here + matrix_ = BackendMatrix::Map(data.data(), rows, cols); } template inline AMatrix::AMatrix(size_t rows, size_t cols, const std::vector& data) { - matrix_ = arma::Mat(&data[0], (arma::uword)rows, (arma::uword)cols); + matrix_ = BackendMatrix::Map(data.data(), rows, cols); } template inline AMatrix::AMatrix(size_t rows, size_t cols) { - matrix_ = arma::Mat((arma::uword)rows, (arma::uword)cols); + matrix_ = BackendMatrix(rows, cols); } template -inline AMatrix::AMatrix(arma::Mat&& matrix) { +inline AMatrix::AMatrix(BackendMatrix&& matrix) { matrix_ = std::move(matrix); } template AMatrix AMatrix::GetSpan(size_t rowStart, size_t rowEnd, size_t colStart, size_t colEnd) const { - arma::Mat m = matrix_.submat(rowStart, colStart, rowEnd, colEnd); + size_t num_rows = rowEnd - rowStart + 1; + size_t num_cols = colEnd - colStart + 1; + BackendMatrix m = matrix_.block(rowStart, colStart, num_rows, num_cols); return AMatrix(m); } template inline AMatrix AMatrix::Filled(size_t rows, size_t cols, T initialValue) { - arma::Mat m((arma::uword)rows, (arma::uword)cols); + BackendMatrix m (rows, cols); m.fill(initialValue); - AMatrix am(std::move(m)); - return am; + return AMatrix(std::move(m)); } template inline T& AMatrix::operator()(size_t row, size_t column) { - return matrix_((arma::uword)row, (arma::uword)column); + return matrix_(row, column); } template inline T AMatrix::operator()(size_t row, size_t column) const { - return matrix_((arma::uword)row, (arma::uword)column); + return matrix_(row, column); } template inline T& AMatrix::operator()(size_t elementIndex) { - return matrix_.at((arma::uword)elementIndex); + return *(matrix_.data() + elementIndex); } template inline T AMatrix::operator()(size_t elementIndex) const { - return matrix_((arma::uword)elementIndex); + return *(matrix_.data() + elementIndex); } template @@ -124,281 +126,309 @@ inline AMatrix& AMatrix::operator=(const AMatrix& other) { template inline bool AMatrix::operator==(const AMatrix& other) const { - if (matrix_.n_rows != other.matrix_.n_rows) return false; - if (matrix_.n_cols != other.matrix_.n_cols) return true; - return std::equal(matrix_.cbegin(), matrix_.cend(), other.matrix_.cbegin()); - // Why doesn't == work when documentation says it does? matrix_ == - // other.matrix_; + if (matrix_.rows() != other.matrix_.rows()) return false; + if (matrix_.cols() != other.matrix_.cols()) return false; + return matrix_ == other.matrix_; } template inline AMatrix AMatrix::operator+(const AMatrix& other) const { - return AMatrix(matrix_ + other.matrix_); + return AMatrix((matrix_.array() + other.matrix_.array()).matrix()); } template inline AMatrix AMatrix::operator+(T v) const { - return AMatrix(matrix_ + v); + return AMatrix(matrix_.array() + v); } template inline AMatrix AMatrix::operator*(T v) const { - return AMatrix(matrix_ * v); + return AMatrix(matrix_.array() * v); } template inline AMatrix AMatrix::operator-(T v) const { - return AMatrix(matrix_ - v); + return AMatrix(matrix_.array() - v); } template inline AMatrix AMatrix::operator/(T v) const { - return AMatrix(matrix_ / v); + return AMatrix(matrix_.array() / v); } template inline AMatrix AMatrix::operator-(const AMatrix& m) const { - return AMatrix(matrix_ - m.matrix_); + return AMatrix((matrix_.array() - m.matrix_.array()).matrix()); } template inline AMatrix AMatrix::PointWiseProduct(const AMatrix& m) const { - return AMatrix(std::move(matrix_ % m.matrix_)); + return AMatrix(std::move(matrix_.cwiseProduct(m.matrix_))); } template inline AMatrix AMatrix::PointWiseDivide(const AMatrix& m) const { - return AMatrix(std::move(matrix_ / m.matrix_)); + return AMatrix(std::move(matrix_.array() / m.matrix_.array())); } template inline AMatrix AMatrix::Transpose() const { - return AMatrix{std::move(trans(matrix_))}; + return AMatrix{std::move(matrix_.transpose())}; } template inline std::vector AMatrix::RowSubset(size_t rowIndex, size_t startColumnIndex, size_t endColumnIndex) const { - std::vector vec(arma::conv_to>::from( - matrix_.row(rowIndex).subvec(startColumnIndex, endColumnIndex))); + std::vector vec; + vec.resize(endColumnIndex - startColumnIndex + 1); + for (size_t colIndex = startColumnIndex; colIndex <= endColumnIndex; ++colIndex) { + vec[colIndex - startColumnIndex] = matrix_(rowIndex, colIndex); + } return vec; } template inline size_t AMatrix::LongestDimensionLength() const { - return (matrix_.n_rows > matrix_.n_cols) ? matrix_.n_rows : matrix_.n_cols; + return (matrix_.rows() > matrix_.cols()) ? matrix_.rows() : matrix_.cols(); } template <> inline AMatrix AMatrix::Abs() const { - AMatrix absMatrix(matrix_.n_rows, matrix_.n_cols); - for (size_t i = 0; i < absMatrix.NumElements(); i++) { - absMatrix.matrix_(i) = std::abs(matrix_(i)); - } - return absMatrix; + return AMatrix(matrix_.cwiseAbs()); } template <> inline AMatrix AMatrix>::Abs() const { - arma::Mat absMatrix; - absMatrix.set_size(matrix_.n_rows, matrix_.n_cols); - for (size_t i = 0; i < absMatrix.n_elem; i++) { - absMatrix(i) = std::abs(matrix_(i)); + BackendMatrix absMatrix (matrix_.rows(), matrix_.cols()); + for (size_t rowIndex = 0; rowIndex < matrix_.rows(); rowIndex++) { + for (size_t colIndex = 0; colIndex < matrix_.rows(); colIndex++) { + absMatrix(rowIndex, colIndex) = std::abs(matrix_(rowIndex, colIndex)); + } } return AMatrix(std::move(absMatrix)); } template inline std::vector AMatrix::GetRow(size_t row) const { - std::vector vec(arma::conv_to>::from(matrix_.row(row))); + std::vector vec; + vec.resize(matrix_.cols()); + for (size_t i = 0; i < matrix_.cols(); ++i) + { + vec[i] = matrix_(row, i); + } return vec; } template inline AMatrix AMatrix::GetRows(size_t rowStart, size_t rowEnd) const { - return AMatrix(std::move(matrix_.rows(rowStart, rowEnd))); + return AMatrix(std::move(matrix_.middleRows(rowStart, rowEnd - rowStart + 1))); } template inline AMatrix AMatrix::GetColumn(size_t column) const { - return AMatrix(matrix_.cols(column, column)); + return AMatrix(matrix_.col(column)); } template inline AMatrix AMatrix::GetColumns(size_t colStart, size_t colEnd) const { - return AMatrix(matrix_.cols(colStart, colEnd)); + return AMatrix(matrix_.middleCols(colStart, colEnd - colStart + 1)); } template inline void AMatrix::SetRow(size_t rowIndex, const std::vector& row) { - matrix_.row(rowIndex) = std::move(arma::Row(row)); + matrix_.row(rowIndex) = BackendMatrix::Map(row.data(), 1, row.size()); } template inline void AMatrix::SetColumn(size_t colIndex, AMatrix&& col) { - matrix_.col(colIndex) = std::move(col.GetArmaMat()); + matrix_.col(colIndex) = std::move(col.matrix_); } template inline void AMatrix::SetColumn(size_t colIndex, std::vector&& col) { - matrix_.col(colIndex) = std::move(arma::Col(col)); + matrix_.col(colIndex) = std::move(BackendMatrix::Map(col.data(), col.size(), 1)); } template inline void AMatrix::SetColumn(size_t colIndex, std::valarray&& col) { - std::vector v; - v.reserve(col.size()); - v.assign(std::begin(col), std::end(col)); - matrix_.col(colIndex) = std::move(arma::Col(v)); + for (size_t i = 0; i < col.size(); ++i) { + matrix_(i, colIndex) = col[i]; + } } template inline void AMatrix::SetRow(size_t rowIndex, std::valarray&& row) { - std::vector v; - v.reserve(row.size()); - v.assign(std::begin(row), std::end(row)); - matrix_.row(rowIndex) = std::move(arma::Row(v)); + for (size_t colIndex = 0; colIndex < matrix_.cols(); ++colIndex) { + matrix_(rowIndex, colIndex) = row[colIndex]; + } } template void AMatrix::Print() const { printf("\n"); - matrix_.print(); + std::cout << matrix_ << std::endl; } template <> void AMatrix>::PrintSummary(const char* s) const { printf("%s\n", s); - size_t outMatSize = matrix_.n_rows; + size_t outMatSize = matrix_.rows(); printf("first five\n"); for (size_t i = 0; i < 5; i++) { - printf("complex[%2zu] = %9.20f , %9.20f\n", i, matrix_(i).real(), - matrix_(i).imag()); + printf("complex[%2zu] = %9.20f , %9.20f\n", i, (matrix_.data() + i)->real(), + (matrix_.data() + i)->imag()); } printf("middle \n"); for (size_t i = (outMatSize / 2) - 4; i < (outMatSize / 2) + 6; i++) { - printf("complex[%2zu] = %9.20f , %9.20f\n", i, matrix_(i).real(), - matrix_(i).imag()); + printf("complex[%2zu] = %9.20f , %9.20f\n", i, (matrix_.data() + i)->real(), + (matrix_.data() + i)->imag()); } printf("last five\n"); for (size_t i = outMatSize - 6; i < outMatSize; i++) { - printf("complex[%2zu] = %9.20f , %9.20f\n", i, matrix_(i).real(), - matrix_(i).imag()); + printf("complex[%2zu] = %9.20f , %9.20f\n", i, (matrix_.data() + i)->real(), + (matrix_.data() + i)->imag()); } } template <> void AMatrix::PrintSummary(const char* s) const { printf("%s\n", s); - size_t outMatSize = matrix_.n_rows; + size_t outMatSize = matrix_.rows(); printf("first five\n"); for (size_t i = 0; i < 5; i++) { - printf("double[%2zu] = %9.20f\n", i, matrix_(i)); + printf("double[%2zu] = %9.20f\n", i, *(matrix_.data() + i)); } printf("middle \n"); for (size_t i = (outMatSize / 2) - 4; i < (outMatSize / 2) + 6; i++) { - printf("double[%2zu] = %9.20f\n", i, matrix_(i)); + printf("double[%2zu] = %9.20f\n", i, *(matrix_.data() + i)); } printf("last five\n"); for (size_t i = outMatSize - 6; i < outMatSize; i++) { - printf("double[%2zu] = %9.20f\n", i, matrix_(i)); + printf("double[%2zu] = %9.20f\n", i, *(matrix_.data() + i)); } } template inline const T* AMatrix::MemPtr() const { - return matrix_.memptr(); + return matrix_.data(); } template inline void AMatrix::Resize(const size_t rows, const size_t cols) { - matrix_.resize(rows, cols); + // We need to try to keep the same data + matrix_.conservativeResize(rows, cols); } template inline AMatrix AMatrix::JoinVertically(const AMatrix& other) const { - // Having a separate line for return is needed to cast to Mat - arma::Mat m = arma::join_vert(matrix_, other.GetArmaMat()); + // Asserting other matrix has the same number of columns + if (matrix_.cols() != other.matrix_.cols()) return AMatrix (); + size_t numCols = matrix_.cols(); + size_t numRows = matrix_.rows() + other.matrix_.rows(); + BackendMatrix m (numRows, numCols); + m.topRows(matrix_.rows()) = matrix_; + m.bottomRows(other.matrix_.rows()) = other.matrix_; return m; } template inline AMatrix AMatrix::FlipUpDown() const { - return AMatrix(arma::flipud(matrix_)); + return AMatrix(matrix_.colwise().reverse()); } template inline AMatrix AMatrix::Mean(kDimension dim) const { - return AMatrix(arma::mean(matrix_, static_cast(dim))); + if (dim == kDimension::COLUMN) { + return AMatrix(matrix_.colwise().mean()); + } + else { // if (dim == kDimension::ROW) + return AMatrix(matrix_.rowwise().mean()); + } } template inline AMatrix AMatrix::StdDev(kDimension dim) const { // The second parameter of arma::stddev is norm_type. // norm_type=0 means that stddev should use the unbiased estimate. - return AMatrix(arma::stddev(matrix_, 0, static_cast(dim))); + if (dim == kDimension::COLUMN) { + if (matrix_.rows() == 1) { + return AMatrix(BackendMatrix::Zero(1, matrix_.cols())); + } + else { + return AMatrix((matrix_.rowwise() - matrix_.colwise().mean()).colwise().norm()/std::sqrt((double)matrix_.rows()-1.0)); + } + } + else { // if (dim == kDimension::ROW) + if (matrix_.cols() == 1) { + return AMatrix(BackendMatrix::Zero(matrix_.rows(), 1)); + } + else { + return AMatrix((matrix_.colwise() - matrix_.rowwise().mean()).rowwise().norm()/std::sqrt((double)matrix_.cols()-1.0)); + } + } } template -inline const arma::Mat& AMatrix::GetArmaMat() const { +inline const BackendMatrix& AMatrix::GetBackendMat() const { return matrix_; } template inline std::vector AMatrix::ToVector() const { - return arma::conv_to>::from(matrix_.col(0)); + std::vector v (static_cast(matrix_.rows())); + for (size_t rowIndex = 0; rowIndex < matrix_.rows(); ++rowIndex) { + v[rowIndex] = matrix_(rowIndex, 0); + } + return std::move(v); } template inline std::valarray AMatrix::ToValArray() const { - std::vector v = arma::conv_to>::from(matrix_.col(0)); - return std::valarray(v.data(), v.size()); -} - -template <> -inline std::vector> -AMatrix>::ToVector() const { - return arma::conv_to>>::from(matrix_.col(0)); + std::valarray v (static_cast(matrix_.rows())); + for (size_t rowIndex = 0; rowIndex < matrix_.rows(); ++rowIndex) { + v[rowIndex] = matrix_(rowIndex, 0); + } + return std::move(v); } template inline size_t AMatrix::NumRows() const { - return matrix_.n_rows; + return matrix_.rows(); } template inline size_t AMatrix::NumCols() const { - return matrix_.n_cols; + return matrix_.cols(); } template inline size_t AMatrix::NumElements() const { - return matrix_.n_elem; + return matrix_.size(); } template inline typename AMatrix::iterator AMatrix::begin() { - return matrix_.begin(); + return matrix_.data(); } template inline typename AMatrix::iterator AMatrix::end() { - return matrix_.end(); + return matrix_.data() + matrix_.size(); } template inline typename AMatrix::const_iterator AMatrix::cbegin() const { - return matrix_.cbegin(); + return matrix_.data(); } template inline typename AMatrix::const_iterator AMatrix::cend() const { - return matrix_.cend(); + return matrix_.data() + matrix_.size(); } template inline const T* AMatrix::data() const { - return matrix_.mem; + return matrix_.data(); } template inline T* AMatrix::mutData() const { - return const_cast(matrix_.mem); + return const_cast(matrix_.data()); } template class AMatrix; diff --git a/src/include/amatrix.h b/src/include/amatrix.h index 0838f8b..341c821 100644 --- a/src/include/amatrix.h +++ b/src/include/amatrix.h @@ -17,13 +17,12 @@ #ifndef VISQOL_INCLUDE_AMATRIX_H #define VISQOL_INCLUDE_AMATRIX_H -#include +#include "Eigen/Dense" #include #include #include #include "absl/types/span.h" -#define ARMA_64BIT_WORD #if defined(_MSC_VER) && _MSC_VER >= 1400 #pragma warning(push) @@ -33,6 +32,10 @@ namespace Visqol { enum class kDimension { COLUMN = 0, ROW = 1 }; +// Define an alias for the Eigen matrix +template +using BackendMatrix = Eigen::Matrix; + template class AMatrix; template @@ -43,7 +46,7 @@ template class AMatrix { public: AMatrix() {} - AMatrix(const arma::Mat& mat); + AMatrix(const BackendMatrix& mat); AMatrix(const AMatrix& other); AMatrix(const std::vector& col); AMatrix(const absl::Span& col); @@ -52,7 +55,7 @@ class AMatrix { AMatrix(size_t rows, size_t cols); AMatrix(size_t rows, size_t cols, std::vector&& data); AMatrix(size_t rows, size_t cols, const std::vector& data); - AMatrix(arma::Mat&& matrix); // could this be private? + AMatrix(BackendMatrix&& matrix); // could this be private? T& operator()(size_t row, size_t column); T operator()(size_t row, size_t column) const; T& operator()(size_t elementIndex); @@ -104,11 +107,11 @@ class AMatrix { std::valarray ToValArray() const; // hack to access private member - const arma::Mat& GetArmaMat() const; + const BackendMatrix& GetBackendMat() const; public: - typedef typename arma::Mat::iterator iterator; - typedef typename arma::Mat::const_iterator const_iterator; + using iterator = T*; + using const_iterator = const T*; iterator begin(); iterator end(); const_iterator cbegin() const; @@ -118,7 +121,7 @@ class AMatrix { T* mutData() const; // bit of a hack private: - arma::Mat matrix_; + BackendMatrix matrix_; }; } // namespace Visqol