You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
PaddleSpeech/runtime/engine/common/matrix/kaldi-vector.cc

1240 lines
40 KiB

// matrix/kaldi-vector.cc
// Copyright 2009-2011 Microsoft Corporation; Lukas Burget;
// Saarland University; Go Vivace Inc.; Ariya Rastrow;
// Petr Schwarz; Yanmin Qian; Jan Silovsky;
// Haihua Xu; Wei Shi
// 2015 Guoguo Chen
// 2017 Daniel Galvez
// 2019 Yiwen Shao
// See ../../COPYING for clarification regarding multiple authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
// WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
// MERCHANTABLITY OR NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing permissions and
// limitations under the License.
#include "matrix/kaldi-vector.h"
#include <algorithm>
#include <string>
#include "matrix/kaldi-matrix.h"
namespace kaldi {
template <typename Real>
inline void Vector<Real>::Init(const MatrixIndexT dim) {
KALDI_ASSERT(dim >= 0);
if (dim == 0) {
this->dim_ = 0;
this->data_ = NULL;
return;
}
MatrixIndexT size;
void *data;
void *free_data;
size = dim * sizeof(Real);
if ((data = KALDI_MEMALIGN(16, size, &free_data)) != NULL) {
this->data_ = static_cast<Real *>(data);
this->dim_ = dim;
} else {
throw std::bad_alloc();
}
}
template <typename Real>
void Vector<Real>::Resize(const MatrixIndexT dim,
MatrixResizeType resize_type) {
// the next block uses recursion to handle what we have to do if
// resize_type == kCopyData.
if (resize_type == kCopyData) {
if (this->data_ == NULL || dim == 0)
resize_type = kSetZero; // nothing to copy.
else if (this->dim_ == dim) {
return;
} // nothing to do.
else {
// set tmp to a vector of the desired size.
Vector<Real> tmp(dim, kUndefined);
if (dim > this->dim_) {
memcpy(tmp.data_, this->data_, sizeof(Real) * this->dim_);
memset(tmp.data_ + this->dim_,
0,
sizeof(Real) * (dim - this->dim_));
} else {
memcpy(tmp.data_, this->data_, sizeof(Real) * dim);
}
tmp.Swap(this);
// and now let tmp go out of scope, deleting what was in *this.
return;
}
}
// At this point, resize_type == kSetZero or kUndefined.
if (this->data_ != NULL) {
if (this->dim_ == dim) {
if (resize_type == kSetZero) this->SetZero();
return;
} else {
Destroy();
}
}
Init(dim);
if (resize_type == kSetZero) this->SetZero();
}
/// Copy data from another vector
template <typename Real>
void VectorBase<Real>::CopyFromVec(const VectorBase<Real> &v) {
KALDI_ASSERT(Dim() == v.Dim());
if (data_ != v.data_) {
std::memcpy(this->data_, v.data_, dim_ * sizeof(Real));
}
}
/*
template<typename Real>
template<typename OtherReal>
void VectorBase<Real>::CopyFromPacked(const PackedMatrix<OtherReal>& M) {
SubVector<OtherReal> v(M);
this->CopyFromVec(v);
}
// instantiate the template.
template void VectorBase<float>::CopyFromPacked(const PackedMatrix<double>
&other);
template void VectorBase<float>::CopyFromPacked(const PackedMatrix<float>
&other);
template void VectorBase<double>::CopyFromPacked(const PackedMatrix<double>
&other);
template void VectorBase<double>::CopyFromPacked(const PackedMatrix<float>
&other);
/// Load data into the vector
template<typename Real>
void VectorBase<Real>::CopyFromPtr(const Real *data, MatrixIndexT sz) {
KALDI_ASSERT(dim_ == sz);
std::memcpy(this->data_, data, Dim() * sizeof(Real));
}*/
template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyFromVec(const VectorBase<OtherReal> &other) {
KALDI_ASSERT(dim_ == other.Dim());
Real *__restrict__ ptr = data_;
const OtherReal *__restrict__ other_ptr = other.Data();
for (MatrixIndexT i = 0; i < dim_; i++) ptr[i] = other_ptr[i];
}
template void VectorBase<float>::CopyFromVec(const VectorBase<double> &other);
template void VectorBase<double>::CopyFromVec(const VectorBase<float> &other);
// Remove element from the vector. The vector is not reallocated
template <typename Real>
void Vector<Real>::RemoveElement(MatrixIndexT i) {
KALDI_ASSERT(i < this->dim_ && "Access out of vector");
for (MatrixIndexT j = i + 1; j < this->dim_; j++)
this->data_[j - 1] = this->data_[j];
this->dim_--;
}
/// Deallocates memory and sets object to empty vector.
template <typename Real>
void Vector<Real>::Destroy() {
/// we need to free the data block if it was defined
if (this->data_ != NULL) KALDI_MEMALIGN_FREE(this->data_);
this->data_ = NULL;
this->dim_ = 0;
}
template <typename Real>
void VectorBase<Real>::SetZero() {
std::memset(data_, 0, dim_ * sizeof(Real));
}
template <typename Real>
bool VectorBase<Real>::IsZero(Real cutoff) const {
Real abs_max = 0.0;
for (MatrixIndexT i = 0; i < Dim(); i++)
abs_max = std::max(std::abs(data_[i]), abs_max);
return (abs_max <= cutoff);
}
/*
template<typename Real>
void VectorBase<Real>::SetRandn() {
kaldi::RandomState rstate;
MatrixIndexT last = (Dim() % 2 == 1) ? Dim() - 1 : Dim();
for (MatrixIndexT i = 0; i < last; i += 2) {
kaldi::RandGauss2(data_ + i, data_ + i + 1, &rstate);
}
if (Dim() != last) data_[last] = static_cast<Real>(kaldi::RandGauss(&rstate));
}
template<typename Real>
void VectorBase<Real>::SetRandUniform() {
kaldi::RandomState rstate;
for (MatrixIndexT i = 0; i < Dim(); i++) {
*(data_+i) = RandUniform(&rstate);
}
}
template<typename Real>
MatrixIndexT VectorBase<Real>::RandCategorical() const {
kaldi::RandomState rstate;
Real sum = this->Sum();
KALDI_ASSERT(this->Min() >= 0.0 && sum > 0.0);
Real r = RandUniform(&rstate) * sum;
Real *data = this->data_;
MatrixIndexT dim = this->dim_;
Real running_sum = 0.0;
for (MatrixIndexT i = 0; i < dim; i++) {
running_sum += data[i];
if (r < running_sum) return i;
}
return dim_ - 1; // Should only happen if RandUniform()
// returns exactly 1, or due to roundoff.
}*/
template <typename Real>
void VectorBase<Real>::Set(Real f) {
// Why not use memset here?
// The basic unit of memset is a byte.
// If f != 0 and sizeof(Real) > 1, then we cannot use memset.
if (f == 0) {
this->SetZero(); // calls std::memset
} else {
for (MatrixIndexT i = 0; i < dim_; i++) {
data_[i] = f;
}
}
}
template <typename Real>
void VectorBase<Real>::CopyRowsFromMat(const MatrixBase<Real> &mat) {
KALDI_ASSERT(dim_ == mat.NumCols() * mat.NumRows());
Real *inc_data = data_;
const MatrixIndexT cols = mat.NumCols(), rows = mat.NumRows();
if (mat.Stride() == mat.NumCols()) {
memcpy(inc_data, mat.Data(), cols * rows * sizeof(Real));
} else {
for (MatrixIndexT i = 0; i < rows; i++) {
// copy the data to the propper position
memcpy(inc_data, mat.RowData(i), cols * sizeof(Real));
// set new copy position
inc_data += cols;
}
}
}
template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyRowsFromMat(const MatrixBase<OtherReal> &mat) {
KALDI_ASSERT(dim_ == mat.NumCols() * mat.NumRows());
Real *vec_data = data_;
const MatrixIndexT cols = mat.NumCols(), rows = mat.NumRows();
for (MatrixIndexT i = 0; i < rows; i++) {
const OtherReal *mat_row = mat.RowData(i);
for (MatrixIndexT j = 0; j < cols; j++) {
vec_data[j] = static_cast<Real>(mat_row[j]);
}
vec_data += cols;
}
}
template void VectorBase<float>::CopyRowsFromMat(const MatrixBase<double> &mat);
template void VectorBase<double>::CopyRowsFromMat(const MatrixBase<float> &mat);
template <typename Real>
void VectorBase<Real>::CopyColsFromMat(const MatrixBase<Real> &mat) {
KALDI_ASSERT(dim_ == mat.NumCols() * mat.NumRows());
Real *inc_data = data_;
const MatrixIndexT cols = mat.NumCols(), rows = mat.NumRows(),
stride = mat.Stride();
const Real *mat_inc_data = mat.Data();
for (MatrixIndexT i = 0; i < cols; i++) {
for (MatrixIndexT j = 0; j < rows; j++) {
inc_data[j] = mat_inc_data[j * stride];
}
mat_inc_data++;
inc_data += rows;
}
}
template <typename Real>
void VectorBase<Real>::CopyRowFromMat(const MatrixBase<Real> &mat,
MatrixIndexT row) {
KALDI_ASSERT(row < mat.NumRows());
KALDI_ASSERT(dim_ == mat.NumCols());
const Real *mat_row = mat.RowData(row);
memcpy(data_, mat_row, sizeof(Real) * dim_);
}
template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyRowFromMat(const MatrixBase<OtherReal> &mat,
MatrixIndexT row) {
KALDI_ASSERT(row < mat.NumRows());
KALDI_ASSERT(dim_ == mat.NumCols());
const OtherReal *mat_row = mat.RowData(row);
for (MatrixIndexT i = 0; i < dim_; i++)
data_[i] = static_cast<Real>(mat_row[i]);
}
template void VectorBase<float>::CopyRowFromMat(const MatrixBase<double> &mat,
MatrixIndexT row);
template void VectorBase<double>::CopyRowFromMat(const MatrixBase<float> &mat,
MatrixIndexT row);
/*
template<typename Real>
template<typename OtherReal>
void VectorBase<Real>::CopyRowFromSp(const SpMatrix<OtherReal> &sp, MatrixIndexT
row) {
KALDI_ASSERT(row < sp.NumRows());
KALDI_ASSERT(dim_ == sp.NumCols());
const OtherReal *sp_data = sp.Data();
sp_data += (row*(row+1)) / 2; // takes us to beginning of this row.
MatrixIndexT i;
for (i = 0; i < row; i++) // copy consecutive elements.
data_[i] = static_cast<Real>(*(sp_data++));
for(; i < dim_; ++i, sp_data += i)
data_[i] = static_cast<Real>(*sp_data);
}
template
void VectorBase<float>::CopyRowFromSp(const SpMatrix<double> &mat, MatrixIndexT
row);
template
void VectorBase<double>::CopyRowFromSp(const SpMatrix<float> &mat, MatrixIndexT
row);
template
void VectorBase<float>::CopyRowFromSp(const SpMatrix<float> &mat, MatrixIndexT
row);
template
void VectorBase<double>::CopyRowFromSp(const SpMatrix<double> &mat, MatrixIndexT
row);
// takes absolute value of the elements to a power.
// Throws exception if could not (but only for power != 1 and power != 2).
template<typename Real>
void VectorBase<Real>::ApplyPowAbs(Real power, bool include_sign) {
if (power == 1.0)
for (MatrixIndexT i = 0; i < dim_; i++)
data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) * std::abs(data_[i]);
if (power == 2.0) {
for (MatrixIndexT i = 0; i < dim_; i++)
data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) * data_[i] * data_[i];
} else if (power == 0.5) {
for (MatrixIndexT i = 0; i < dim_; i++) {
data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) *
std::sqrt(std::abs(data_[i]));
}
} else if (power < 0.0) {
for (MatrixIndexT i = 0; i < dim_; i++) {
data_[i] = (data_[i] == 0.0 ? 0.0 : pow(std::abs(data_[i]), power));
data_[i] *= (include_sign && data_[i] < 0 ? -1 : 1);
if (data_[i] == HUGE_VAL) { // HUGE_VAL is what errno returns on error.
KALDI_ERR << "Could not raise element " << i << "to power "
<< power << ": returned value = " << data_[i];
}
}
} else {
for (MatrixIndexT i = 0; i < dim_; i++) {
data_[i] = (include_sign && data_[i] < 0 ? -1 : 1) *
pow(std::abs(data_[i]), power);
if (data_[i] == HUGE_VAL) { // HUGE_VAL is what errno returns on error.
KALDI_ERR << "Could not raise element " << i << "to power "
<< power << ": returned value = " << data_[i];
}
}
}
}
// Computes the p-th norm. Throws exception if could not.
template<typename Real>
Real VectorBase<Real>::Norm(Real p) const {
KALDI_ASSERT(p >= 0.0);
Real sum = 0.0;
if (p == 0.0) {
for (MatrixIndexT i = 0; i < dim_; i++)
if (data_[i] != 0.0) sum += 1.0;
return sum;
} else if (p == 1.0) {
for (MatrixIndexT i = 0; i < dim_; i++)
sum += std::abs(data_[i]);
return sum;
} else if (p == 2.0) {
for (MatrixIndexT i = 0; i < dim_; i++)
sum += data_[i] * data_[i];
return std::sqrt(sum);
} else if (p == std::numeric_limits<Real>::infinity()){
for (MatrixIndexT i = 0; i < dim_; i++)
sum = std::max(sum, std::abs(data_[i]));
return sum;
} else {
Real tmp;
bool ok = true;
for (MatrixIndexT i = 0; i < dim_; i++) {
tmp = pow(std::abs(data_[i]), p);
if (tmp == HUGE_VAL) // HUGE_VAL is what pow returns on error.
ok = false;
sum += tmp;
}
tmp = pow(sum, static_cast<Real>(1.0/p));
KALDI_ASSERT(tmp != HUGE_VAL); // should not happen here.
if (ok) {
return tmp;
} else {
Real maximum = this->Max(), minimum = this->Min(),
max_abs = std::max(maximum, -minimum);
KALDI_ASSERT(max_abs > 0); // Or should not have reached here.
Vector<Real> tmp(*this);
tmp.Scale(1.0 / max_abs);
return tmp.Norm(p) * max_abs;
}
}
}
template<typename Real>
bool VectorBase<Real>::ApproxEqual(const VectorBase<Real> &other, float tol)
const {
if (dim_ != other.dim_) KALDI_ERR << "ApproxEqual: size mismatch "
<< dim_ << " vs. " << other.dim_;
KALDI_ASSERT(tol >= 0.0);
if (tol != 0.0) {
Vector<Real> tmp(*this);
tmp.AddVec(-1.0, other);
return (tmp.Norm(2.0) <= static_cast<Real>(tol) * this->Norm(2.0));
} else { // Test for exact equality.
const Real *data = data_;
const Real *other_data = other.data_;
for (MatrixIndexT dim = dim_, i = 0; i < dim; i++)
if (data[i] != other_data[i]) return false;
return true;
}
}
template<typename Real>
Real VectorBase<Real>::Max() const {
Real ans = - std::numeric_limits<Real>::infinity();
const Real *data = data_;
MatrixIndexT i, dim = dim_;
for (i = 0; i + 4 <= dim; i += 4) {
Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
if (a1 > ans || a2 > ans || a3 > ans || a4 > ans) {
Real b1 = (a1 > a2 ? a1 : a2), b2 = (a3 > a4 ? a3 : a4);
if (b1 > ans) ans = b1;
if (b2 > ans) ans = b2;
}
}
for (; i < dim; i++)
if (data[i] > ans) ans = data[i];
return ans;
}
template<typename Real>
Real VectorBase<Real>::Max(MatrixIndexT *index_out) const {
if (dim_ == 0) KALDI_ERR << "Empty vector";
Real ans = - std::numeric_limits<Real>::infinity();
MatrixIndexT index = 0;
const Real *data = data_;
MatrixIndexT i, dim = dim_;
for (i = 0; i + 4 <= dim; i += 4) {
Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
if (a1 > ans || a2 > ans || a3 > ans || a4 > ans) {
if (a1 > ans) { ans = a1; index = i; }
if (a2 > ans) { ans = a2; index = i + 1; }
if (a3 > ans) { ans = a3; index = i + 2; }
if (a4 > ans) { ans = a4; index = i + 3; }
}
}
for (; i < dim; i++)
if (data[i] > ans) { ans = data[i]; index = i; }
*index_out = index;
return ans;
}
template<typename Real>
Real VectorBase<Real>::Min() const {
Real ans = std::numeric_limits<Real>::infinity();
const Real *data = data_;
MatrixIndexT i, dim = dim_;
for (i = 0; i + 4 <= dim; i += 4) {
Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
if (a1 < ans || a2 < ans || a3 < ans || a4 < ans) {
Real b1 = (a1 < a2 ? a1 : a2), b2 = (a3 < a4 ? a3 : a4);
if (b1 < ans) ans = b1;
if (b2 < ans) ans = b2;
}
}
for (; i < dim; i++)
if (data[i] < ans) ans = data[i];
return ans;
}
template<typename Real>
Real VectorBase<Real>::Min(MatrixIndexT *index_out) const {
if (dim_ == 0) KALDI_ERR << "Empty vector";
Real ans = std::numeric_limits<Real>::infinity();
MatrixIndexT index = 0;
const Real *data = data_;
MatrixIndexT i, dim = dim_;
for (i = 0; i + 4 <= dim; i += 4) {
Real a1 = data[i], a2 = data[i+1], a3 = data[i+2], a4 = data[i+3];
if (a1 < ans || a2 < ans || a3 < ans || a4 < ans) {
if (a1 < ans) { ans = a1; index = i; }
if (a2 < ans) { ans = a2; index = i + 1; }
if (a3 < ans) { ans = a3; index = i + 2; }
if (a4 < ans) { ans = a4; index = i + 3; }
}
}
for (; i < dim; i++)
if (data[i] < ans) { ans = data[i]; index = i; }
*index_out = index;
return ans;
}*/
template <typename Real>
template <typename OtherReal>
void VectorBase<Real>::CopyColFromMat(const MatrixBase<OtherReal> &mat,
MatrixIndexT col) {
KALDI_ASSERT(col < mat.NumCols());
KALDI_ASSERT(dim_ == mat.NumRows());
for (MatrixIndexT i = 0; i < dim_; i++) data_[i] = mat(i, col);
// can't do this very efficiently so don't really bother. could improve this
// though.
}
// instantiate the template above.
template void VectorBase<float>::CopyColFromMat(const MatrixBase<float> &mat,
MatrixIndexT col);
template void VectorBase<float>::CopyColFromMat(const MatrixBase<double> &mat,
MatrixIndexT col);
template void VectorBase<double>::CopyColFromMat(const MatrixBase<float> &mat,
MatrixIndexT col);
template void VectorBase<double>::CopyColFromMat(const MatrixBase<double> &mat,
MatrixIndexT col);
// template<typename Real>
// void VectorBase<Real>::CopyDiagFromMat(const MatrixBase<Real> &M) {
// KALDI_ASSERT(dim_ == std::min(M.NumRows(), M.NumCols()));
// cblas_Xcopy(dim_, M.Data(), M.Stride() + 1, data_, 1);
//}
// template<typename Real>
// void VectorBase<Real>::CopyDiagFromPacked(const PackedMatrix<Real> &M) {
// KALDI_ASSERT(dim_ == M.NumCols());
// for (MatrixIndexT i = 0; i < dim_; i++)
// data_[i] = M(i, i);
//// could make this more efficient.
//}
// template<typename Real>
// Real VectorBase<Real>::Sum() const {
//// Do a dot-product with a size-1 array with a stride of 0 to
//// implement sum. This allows us to access SIMD operations in a
//// cross-platform way via your BLAS library.
// Real one(1);
// return cblas_Xdot(dim_, data_, 1, &one, 0);
//}
// template<typename Real>
// Real VectorBase<Real>::SumLog() const {
// double sum_log = 0.0;
// double prod = 1.0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// prod *= data_[i];
//// Possible future work (arnab): change these magic values to pre-defined
//// constants
// if (prod < 1.0e-10 || prod > 1.0e+10) {
// sum_log += Log(prod);
// prod = 1.0;
//}
//}
// if (prod != 1.0) sum_log += Log(prod);
// return sum_log;
//}
// template<typename Real>
// void VectorBase<Real>::AddRowSumMat(Real alpha, const MatrixBase<Real> &M,
// Real beta) {
// KALDI_ASSERT(dim_ == M.NumCols());
// MatrixIndexT num_rows = M.NumRows(), stride = M.Stride(), dim = dim_;
// Real *data = data_;
//// implement the function according to a dimension cutoff for computation
/// efficiency
// if (num_rows <= 64) {
// cblas_Xscal(dim, beta, data, 1);
// const Real *m_data = M.Data();
// for (MatrixIndexT i = 0; i < num_rows; i++, m_data += stride)
// cblas_Xaxpy(dim, alpha, m_data, 1, data, 1);
//} else {
// Vector<Real> ones(M.NumRows());
// ones.Set(1.0);
// this->AddMatVec(alpha, M, kTrans, ones, beta);
//}
//}
// template<typename Real>
// void VectorBase<Real>::AddColSumMat(Real alpha, const MatrixBase<Real> &M,
// Real beta) {
// KALDI_ASSERT(dim_ == M.NumRows());
// MatrixIndexT num_cols = M.NumCols();
//// implement the function according to a dimension cutoff for computation
/// efficiency
// if (num_cols <= 64) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// double sum = 0.0;
// const Real *src = M.RowData(i);
// for (MatrixIndexT j = 0; j < num_cols; j++)
// sum += src[j];
// data_[i] = alpha * sum + beta * data_[i];
//}
//} else {
// Vector<Real> ones(M.NumCols());
// ones.Set(1.0);
// this->AddMatVec(alpha, M, kNoTrans, ones, beta);
//}
//}
// template<typename Real>
// Real VectorBase<Real>::LogSumExp(Real prune) const {
// Real sum;
// if (sizeof(sum) == 8) sum = kLogZeroDouble;
// else sum = kLogZeroFloat;
// Real max_elem = Max(), cutoff;
// if (sizeof(Real) == 4) cutoff = max_elem + kMinLogDiffFloat;
// else cutoff = max_elem + kMinLogDiffDouble;
// if (prune > 0.0 && max_elem - prune > cutoff) // explicit pruning...
// cutoff = max_elem - prune;
// double sum_relto_max_elem = 0.0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// BaseFloat f = data_[i];
// if (f >= cutoff)
// sum_relto_max_elem += Exp(f - max_elem);
//}
// return max_elem + Log(sum_relto_max_elem);
//}
// template<typename Real>
// void VectorBase<Real>::InvertElements() {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = static_cast<Real>(1 / data_[i]);
//}
//}
// template<typename Real>
// void VectorBase<Real>::ApplyLog() {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (data_[i] < 0.0)
// KALDI_ERR << "Trying to take log of a negative number.";
// data_[i] = Log(data_[i]);
//}
//}
// template<typename Real>
// void VectorBase<Real>::ApplyLogAndCopy(const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.Dim());
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = Log(v(i));
//}
//}
// template<typename Real>
// void VectorBase<Real>::ApplyExp() {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = Exp(data_[i]);
//}
//}
// template<typename Real>
// void VectorBase<Real>::ApplyAbs() {
// for (MatrixIndexT i = 0; i < dim_; i++) { data_[i] = std::abs(data_[i]); }
//}
// template<typename Real>
// void VectorBase<Real>::Floor(const VectorBase<Real> &v, Real floor_val,
// MatrixIndexT *floored_count) {
// KALDI_ASSERT(dim_ == v.dim_);
// if (floored_count == nullptr) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = std::max(v.data_[i], floor_val);
//}
//} else {
// MatrixIndexT num_floored = 0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (v.data_[i] < floor_val) {
// data_[i] = floor_val;
// num_floored++;
//} else {
// data_[i] = v.data_[i];
//}
//}
//*floored_count = num_floored;
//}
//}
// template<typename Real>
// void VectorBase<Real>::Ceiling(const VectorBase<Real> &v, Real ceil_val,
// MatrixIndexT *ceiled_count) {
// KALDI_ASSERT(dim_ == v.dim_);
// if (ceiled_count == nullptr) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = std::min(v.data_[i], ceil_val);
//}
//} else {
// MatrixIndexT num_changed = 0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (v.data_[i] > ceil_val) {
// data_[i] = ceil_val;
// num_changed++;
//} else {
// data_[i] = v.data_[i];
//}
//}
//*ceiled_count = num_changed;
//}
//}
// template<typename Real>
// MatrixIndexT VectorBase<Real>::ApplyFloor(const VectorBase<Real> &floor_vec)
// {
// KALDI_ASSERT(floor_vec.Dim() == dim_);
// MatrixIndexT num_floored = 0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// if (data_[i] < floor_vec(i)) {
// data_[i] = floor_vec(i);
// num_floored++;
//}
//}
// return num_floored;
//}
// template<typename Real>
// Real VectorBase<Real>::ApplySoftMax() {
// Real max = this->Max(), sum = 0.0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// sum += (data_[i] = Exp(data_[i] - max));
//}
// this->Scale(1.0 / sum);
// return max + Log(sum);
//}
// template<typename Real>
// Real VectorBase<Real>::ApplyLogSoftMax() {
// Real max = this->Max(), sum = 0.0;
// for (MatrixIndexT i = 0; i < dim_; i++) {
// sum += Exp((data_[i] -= max));
//}
// sum = Log(sum);
// this->Add(-1.0 * sum);
// return max + sum;
//}
//#ifdef HAVE_MKL
// template<>
// void VectorBase<float>::Tanh(const VectorBase<float> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// vsTanh(dim_, src.data_, data_);
//}
// template<>
// void VectorBase<double>::Tanh(const VectorBase<double> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// vdTanh(dim_, src.data_, data_);
//}
//#else
// template<typename Real>
// void VectorBase<Real>::Tanh(const VectorBase<Real> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// Real x = src.data_[i];
// if (x > 0.0) {
// Real inv_expx = Exp(-x);
// x = -1.0 + 2.0 / (1.0 + inv_expx * inv_expx);
//} else {
// Real expx = Exp(x);
// x = 1.0 - 2.0 / (1.0 + expx * expx);
//}
// data_[i] = x;
//}
//}
//#endif
//#ifdef HAVE_MKL
//// Implementing sigmoid based on tanh.
// template<>
// void VectorBase<float>::Sigmoid(const VectorBase<float> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// this->CopyFromVec(src);
// this->Scale(0.5);
// vsTanh(dim_, data_, data_);
// this->Add(1.0);
// this->Scale(0.5);
//}
// template<>
// void VectorBase<double>::Sigmoid(const VectorBase<double> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// this->CopyFromVec(src);
// this->Scale(0.5);
// vdTanh(dim_, data_, data_);
// this->Add(1.0);
// this->Scale(0.5);
//}
//#else
// template<typename Real>
// void VectorBase<Real>::Sigmoid(const VectorBase<Real> &src) {
// KALDI_ASSERT(dim_ == src.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// Real x = src.data_[i];
//// We aim to avoid floating-point overflow here.
// if (x > 0.0) {
// x = 1.0 / (1.0 + Exp(-x));
//} else {
// Real ex = Exp(x);
// x = ex / (ex + 1.0);
//}
// data_[i] = x;
//}
//}
//#endif
// template<typename Real>
// void VectorBase<Real>::Add(Real c) {
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] += c;
//}
//}
// template<typename Real>
// void VectorBase<Real>::Scale(Real alpha) {
// cblas_Xscal(dim_, alpha, data_, 1);
//}
// template<typename Real>
// void VectorBase<Real>::MulElements(const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] *= v.data_[i];
//}
//}
// template<typename Real> // Set each element to y = (x == orig ? changed :
// x).
// void VectorBase<Real>::ReplaceValue(Real orig, Real changed) {
// Real *data = data_;
// for (MatrixIndexT i = 0; i < dim_; i++)
// if (data[i] == orig) data[i] = changed;
//}
// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::MulElements(const VectorBase<OtherReal> &v) {
// KALDI_ASSERT(dim_ == v.Dim());
// const OtherReal *other_ptr = v.Data();
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] *= other_ptr[i];
//}
//}
//// instantiate template.
// template
// void VectorBase<float>::MulElements(const VectorBase<double> &v);
// template
// void VectorBase<double>::MulElements(const VectorBase<float> &v);
// template<typename Real>
// void VectorBase<Real>::AddVecVec(Real alpha, const VectorBase<Real> &v,
// const VectorBase<Real> &r, Real beta) {
// KALDI_ASSERT(v.data_ != this->data_ && r.data_ != this->data_);
//// We pretend that v is a band-diagonal matrix.
// KALDI_ASSERT(dim_ == v.dim_ && dim_ == r.dim_);
// cblas_Xgbmv(kNoTrans, dim_, dim_, 0, 0, alpha, v.data_, 1,
// r.data_, 1, beta, this->data_, 1);
//}
// template<typename Real>
// void VectorBase<Real>::DivElements(const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] /= v.data_[i];
//}
//}
// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::DivElements(const VectorBase<OtherReal> &v) {
// KALDI_ASSERT(dim_ == v.Dim());
// const OtherReal *other_ptr = v.Data();
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] /= other_ptr[i];
//}
//}
//// instantiate template.
// template
// void VectorBase<float>::DivElements(const VectorBase<double> &v);
// template
// void VectorBase<double>::DivElements(const VectorBase<float> &v);
// template<typename Real>
// void VectorBase<Real>::AddVecDivVec(Real alpha, const VectorBase<Real> &v,
// const VectorBase<Real> &rr, Real beta) {
// KALDI_ASSERT((dim_ == v.dim_ && dim_ == rr.dim_));
// for (MatrixIndexT i = 0; i < dim_; i++) {
// data_[i] = alpha * v.data_[i]/rr.data_[i] + beta * data_[i] ;
//}
//}
// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::AddVec(const Real alpha, const VectorBase<OtherReal>
// &v) {
// KALDI_ASSERT(dim_ == v.dim_);
//// remove __restrict__ if it causes compilation problems.
// Real *__restrict__ data = data_;
// OtherReal *__restrict__ other_data = v.data_;
// MatrixIndexT dim = dim_;
// if (alpha != 1.0)
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += alpha * other_data[i];
// else
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += other_data[i];
//}
// template
// void VectorBase<float>::AddVec(const float alpha, const VectorBase<double>
// &v);
// template
// void VectorBase<double>::AddVec(const double alpha, const VectorBase<float>
// &v);
// template<typename Real>
// template<typename OtherReal>
// void VectorBase<Real>::AddVec2(const Real alpha, const VectorBase<OtherReal>
// &v) {
// KALDI_ASSERT(dim_ == v.dim_);
//// remove __restrict__ if it causes compilation problems.
// Real *__restrict__ data = data_;
// OtherReal *__restrict__ other_data = v.data_;
// MatrixIndexT dim = dim_;
// if (alpha != 1.0)
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += alpha * other_data[i] * other_data[i];
// else
// for (MatrixIndexT i = 0; i < dim; i++)
// data[i] += other_data[i] * other_data[i];
//}
// template
// void VectorBase<float>::AddVec2(const float alpha, const VectorBase<double>
// &v);
// template
// void VectorBase<double>::AddVec2(const double alpha, const VectorBase<float>
// &v);
template <typename Real>
void VectorBase<Real>::Read(std::istream &is, bool binary) {
// In order to avoid rewriting this, we just declare a Vector and
// use it to read the data, then copy.
Vector<Real> tmp;
tmp.Read(is, binary);
if (tmp.Dim() != Dim())
KALDI_ERR << "VectorBase<Real>::Read, size mismatch " << Dim()
<< " vs. " << tmp.Dim();
CopyFromVec(tmp);
}
template <typename Real>
void Vector<Real>::Read(std::istream &is, bool binary) {
std::ostringstream specific_error;
MatrixIndexT pos_at_start = is.tellg();
if (binary) {
int peekval = Peek(is, binary);
const char *my_token = (sizeof(Real) == 4 ? "FV" : "DV");
char other_token_start = (sizeof(Real) == 4 ? 'D' : 'F');
if (peekval == other_token_start) { // need to instantiate the other
// type to read it.
typedef typename OtherReal<Real>::Real OtherType; // if Real ==
// float,
// OtherType ==
// double, and
// vice versa.
Vector<OtherType> other(this->Dim());
other.Read(is, binary); // add is false at this point.
if (this->Dim() != other.Dim()) this->Resize(other.Dim());
this->CopyFromVec(other);
return;
}
std::string token;
ReadToken(is, binary, &token);
if (token != my_token) {
if (token.length() > 20) token = token.substr(0, 17) + "...";
specific_error << ": Expected token " << my_token << ", got "
<< token;
goto bad;
}
int32 size;
ReadBasicType(is, binary, &size); // throws on error.
if ((MatrixIndexT)size != this->Dim()) this->Resize(size);
if (size > 0)
is.read(reinterpret_cast<char *>(this->data_), sizeof(Real) * size);
if (is.fail()) {
specific_error
<< "Error reading vector data (binary mode); truncated "
"stream? (size = "
<< size << ")";
goto bad;
}
return;
} else { // Text mode reading; format is " [ 1.1 2.0 3.4 ]\n"
std::string s;
is >> s;
// if ((s.compare("DV") == 0) || (s.compare("FV") == 0)) { // Back
// compatibility.
// is >> s; // get dimension
// is >> s; // get "["
// }
if (is.fail()) {
specific_error << "EOF while trying to read vector.";
goto bad;
}
if (s.compare("[]") == 0) {
Resize(0);
return;
} // tolerate this variant.
if (s.compare("[")) {
if (s.length() > 20) s = s.substr(0, 17) + "...";
specific_error << "Expected \"[\" but got " << s;
goto bad;
}
std::vector<Real> data;
while (1) {
int i = is.peek();
if (i == '-' || (i >= '0' && i <= '9')) { // common cases first.
Real r;
is >> r;
if (is.fail()) {
specific_error << "Failed to read number.";
goto bad;
}
if (!std::isspace(is.peek()) && is.peek() != ']') {
specific_error << "Expected whitespace after number.";
goto bad;
}
data.push_back(r);
// But don't eat whitespace... we want to check that it's not
// newlines
// which would be valid only for a matrix.
} else if (i == ' ' || i == '\t') {
is.get();
} else if (i == ']') {
is.get(); // eat the ']'
this->Resize(data.size());
for (size_t j = 0; j < data.size(); j++)
this->data_[j] = data[j];
i = is.peek();
if (static_cast<char>(i) == '\r') {
is.get();
is.get(); // get \r\n (must eat what we wrote)
} else if (static_cast<char>(i) == '\n') {
is.get();
} // get \n (must eat what we wrote)
if (is.fail()) {
KALDI_WARN << "After end of vector data, read error.";
// we got the data we needed, so just warn for this error.
}
return; // success.
} else if (i == -1) {
specific_error << "EOF while reading vector data.";
goto bad;
} else if (i == '\n' || i == '\r') {
specific_error << "Newline found while reading vector (maybe "
"it's a matrix?)";
goto bad;
} else {
is >> s; // read string.
if (!KALDI_STRCASECMP(s.c_str(), "inf") ||
!KALDI_STRCASECMP(s.c_str(), "infinity")) {
data.push_back(std::numeric_limits<Real>::infinity());
KALDI_WARN << "Reading infinite value into vector.";
} else if (!KALDI_STRCASECMP(s.c_str(), "nan")) {
data.push_back(std::numeric_limits<Real>::quiet_NaN());
KALDI_WARN << "Reading NaN value into vector.";
} else {
if (s.length() > 20) s = s.substr(0, 17) + "...";
specific_error << "Expecting numeric vector data, got "
<< s;
goto bad;
}
}
}
}
// we never reach this line (the while loop returns directly).
bad:
KALDI_ERR << "Failed to read vector from stream. " << specific_error.str()
<< " File position at start is " << pos_at_start << ", currently "
<< is.tellg();
}
template <typename Real>
void VectorBase<Real>::Write(std::ostream &os, bool binary) const {
if (!os.good()) {
KALDI_ERR << "Failed to write vector to stream: stream not good";
}
if (binary) {
std::string my_token = (sizeof(Real) == 4 ? "FV" : "DV");
WriteToken(os, binary, my_token);
int32 size = Dim(); // make the size 32-bit on disk.
KALDI_ASSERT(Dim() == (MatrixIndexT)size);
WriteBasicType(os, binary, size);
os.write(reinterpret_cast<const char *>(Data()), sizeof(Real) * size);
} else {
os << " [ ";
for (MatrixIndexT i = 0; i < Dim(); i++) os << (*this)(i) << " ";
os << "]\n";
}
if (!os.good()) KALDI_ERR << "Failed to write vector to stream";
}
// template<typename Real>
// void VectorBase<Real>::AddVec2(const Real alpha, const VectorBase<Real> &v) {
// KALDI_ASSERT(dim_ == v.dim_);
// for (MatrixIndexT i = 0; i < dim_; i++)
// data_[i] += alpha * v.data_[i] * v.data_[i];
//}
//// this <-- beta*this + alpha*M*v.
// template<typename Real>
// void VectorBase<Real>::AddTpVec(const Real alpha, const TpMatrix<Real> &M,
// const MatrixTransposeType trans,
// const VectorBase<Real> &v,
// const Real beta) {
// KALDI_ASSERT(dim_ == v.dim_ && dim_ == M.NumRows());
// if (beta == 0.0) {
// if (&v != this) CopyFromVec(v);
// MulTp(M, trans);
// if (alpha != 1.0) Scale(alpha);
//} else {
// Vector<Real> tmp(v);
// tmp.MulTp(M, trans);
// if (beta != 1.0) Scale(beta); // *this <-- beta * *this
// AddVec(alpha, tmp); // *this += alpha * M * v
//}
//}
// template<typename Real>
// Real VecMatVec(const VectorBase<Real> &v1, const MatrixBase<Real> &M,
// const VectorBase<Real> &v2) {
// KALDI_ASSERT(v1.Dim() == M.NumRows() && v2.Dim() == M.NumCols());
// Vector<Real> vtmp(M.NumRows());
// vtmp.AddMatVec(1.0, M, kNoTrans, v2, 0.0);
// return VecVec(v1, vtmp);
//}
// template
// float VecMatVec(const VectorBase<float> &v1, const MatrixBase<float> &M,
// const VectorBase<float> &v2);
// template
// double VecMatVec(const VectorBase<double> &v1, const MatrixBase<double> &M,
// const VectorBase<double> &v2);
template <typename Real>
void Vector<Real>::Swap(Vector<Real> *other) {
std::swap(this->data_, other->data_);
std::swap(this->dim_, other->dim_);
}
// template<typename Real>
// void VectorBase<Real>::AddDiagMat2(
// Real alpha, const MatrixBase<Real> &M,
// MatrixTransposeType trans, Real beta) {
// if (trans == kNoTrans) {
// KALDI_ASSERT(this->dim_ == M.NumRows());
// MatrixIndexT rows = this->dim_, cols = M.NumCols(),
// mat_stride = M.Stride();
// Real *data = this->data_;
// const Real *mat_data = M.Data();
// for (MatrixIndexT i = 0; i < rows; i++, mat_data += mat_stride, data++)
//*data = beta * *data + alpha * cblas_Xdot(cols,mat_data,1,mat_data,1);
//} else {
// KALDI_ASSERT(this->dim_ == M.NumCols());
// MatrixIndexT rows = M.NumRows(), cols = this->dim_,
// mat_stride = M.Stride();
// Real *data = this->data_;
// const Real *mat_data = M.Data();
// for (MatrixIndexT i = 0; i < cols; i++, mat_data++, data++)
//*data = beta * *data + alpha * cblas_Xdot(rows, mat_data, mat_stride,
// mat_data, mat_stride);
//}
//}
// template<typename Real>
// void VectorBase<Real>::AddDiagMatMat(
// Real alpha,
// const MatrixBase<Real> &M, MatrixTransposeType transM,
// const MatrixBase<Real> &N, MatrixTransposeType transN,
// Real beta) {
// MatrixIndexT dim = this->dim_,
// M_col_dim = (transM == kTrans ? M.NumRows() : M.NumCols()),
// N_row_dim = (transN == kTrans ? N.NumCols() : N.NumRows());
// KALDI_ASSERT(M_col_dim == N_row_dim); // this is the dimension we sum over
// MatrixIndexT M_row_stride = M.Stride(), M_col_stride = 1;
// if (transM == kTrans) std::swap(M_row_stride, M_col_stride);
// MatrixIndexT N_row_stride = N.Stride(), N_col_stride = 1;
// if (transN == kTrans) std::swap(N_row_stride, N_col_stride);
// Real *data = this->data_;
// const Real *Mdata = M.Data(), *Ndata = N.Data();
// for (MatrixIndexT i = 0; i < dim; i++, Mdata += M_row_stride, Ndata +=
// N_col_stride, data++) {
//*data = beta * *data + alpha * cblas_Xdot(M_col_dim, Mdata, M_col_stride,
// Ndata, N_row_stride);
//}
//}
template class Vector<float>;
template class Vector<double>;
template class VectorBase<float>;
template class VectorBase<double>;
} // namespace kaldi