/** * Copyright (c) 2016-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include "densematrix.h" #include #include #include #include #include "utils.h" #include "vector.h" namespace fasttext { DenseMatrix::DenseMatrix() : DenseMatrix(0, 0) {} DenseMatrix::DenseMatrix(int64_t m, int64_t n) : Matrix(m, n), data_(m * n) {} DenseMatrix::DenseMatrix(DenseMatrix&& other) noexcept : Matrix(other.m_, other.n_), data_(std::move(other.data_)) {} DenseMatrix::DenseMatrix(int64_t m, int64_t n, real* dataPtr) : Matrix(m, n), data_(dataPtr, dataPtr + (m * n)) {} void DenseMatrix::zero() { std::fill(data_.begin(), data_.end(), 0.0); } void DenseMatrix::uniformThread(real a, int block, int32_t seed) { std::minstd_rand rng(block + seed); std::uniform_real_distribution<> uniform(-a, a); int64_t blockSize = (m_ * n_) / 10; for (int64_t i = blockSize * block; i < (m_ * n_) && i < blockSize * (block + 1); i++) { data_[i] = uniform(rng); } } void DenseMatrix::uniform(real a, unsigned int thread, int32_t seed) { if (thread > 1) { std::vector threads; for (int i = 0; i < thread; i++) { threads.push_back(std::thread([=]() { uniformThread(a, i, seed); })); } for (int32_t i = 0; i < threads.size(); i++) { threads[i].join(); } } else { // webassembly can't instantiate `std::thread` uniformThread(a, 0, seed); } } void DenseMatrix::multiplyRow(const Vector& nums, int64_t ib, int64_t ie) { if (ie == -1) { ie = m_; } assert(ie <= nums.size()); for (auto i = ib; i < ie; i++) { real n = nums[i - ib]; if (n != 0) { for (auto j = 0; j < n_; j++) { at(i, j) *= n; } } } } void DenseMatrix::divideRow(const Vector& denoms, int64_t ib, int64_t ie) { if (ie == -1) { ie = m_; } assert(ie <= denoms.size()); for (auto i = ib; i < ie; i++) { real n = denoms[i - ib]; if (n != 0) { for (auto j = 0; j < n_; j++) { at(i, j) /= n; } } } } real DenseMatrix::l2NormRow(int64_t i) const { auto norm = 0.0; for (auto j = 0; j < n_; j++) { norm += at(i, j) * at(i, j); } if (std::isnan(norm)) { throw EncounteredNaNError(); } return std::sqrt(norm); } void DenseMatrix::l2NormRow(Vector& norms) const { assert(norms.size() == m_); for (auto i = 0; i < m_; i++) { norms[i] = l2NormRow(i); } } real DenseMatrix::dotRow(const Vector& vec, int64_t i) const { assert(i >= 0); assert(i < m_); assert(vec.size() == n_); real d = 0.0; for (int64_t j = 0; j < n_; j++) { d += at(i, j) * vec[j]; } if (std::isnan(d)) { throw EncounteredNaNError(); } return d; } void DenseMatrix::addVectorToRow(const Vector& vec, int64_t i, real a) { assert(i >= 0); assert(i < m_); assert(vec.size() == n_); for (int64_t j = 0; j < n_; j++) { data_[i * n_ + j] += a * vec[j]; } } void DenseMatrix::addRowToVector(Vector& x, int32_t i) const { assert(i >= 0); assert(i < this->size(0)); assert(x.size() == this->size(1)); for (int64_t j = 0; j < n_; j++) { x[j] += at(i, j); } } void DenseMatrix::addRowToVector(Vector& x, int32_t i, real a) const { assert(i >= 0); assert(i < this->size(0)); assert(x.size() == this->size(1)); for (int64_t j = 0; j < n_; j++) { x[j] += a * at(i, j); } } void DenseMatrix::save(std::ostream& out) const { out.write((char*)&m_, sizeof(int64_t)); out.write((char*)&n_, sizeof(int64_t)); out.write((char*)data_.data(), m_ * n_ * sizeof(real)); } void DenseMatrix::load(std::istream& in) { in.read((char*)&m_, sizeof(int64_t)); in.read((char*)&n_, sizeof(int64_t)); data_ = std::vector(m_ * n_); in.read((char*)data_.data(), m_ * n_ * sizeof(real)); } void DenseMatrix::dump(std::ostream& out) const { out << m_ << " " << n_ << std::endl; for (int64_t i = 0; i < m_; i++) { for (int64_t j = 0; j < n_; j++) { if (j > 0) { out << " "; } out << at(i, j); } out << std::endl; } }; } // namespace fasttext