/* * MatSample.hpp, part of LatAnalyze 3 * * Copyright (C) 2013 - 2020 Antonin Portelli * * LatAnalyze 3 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * LatAnalyze 3 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with LatAnalyze 3. If not, see . */ #ifndef Latan_MatSample_hpp_ #define Latan_MatSample_hpp_ #include #include #include BEGIN_LATAN_NAMESPACE /****************************************************************************** * matrix sample class * ******************************************************************************/ #define SCAL_OP_RETURN(op, s, x) s.unaryExpr(\ std::bind(MatSample::scalar##op,\ std::placeholders::_1, x)) template class MatSample: public Sample> { public: // block type template template class BlockTemplate { private: typedef typename std::remove_const::type NonConstType; public: // constructors BlockTemplate(S &sample, const Index i, const Index j, const Index nRow, const Index nCol); BlockTemplate(BlockTemplate &b); BlockTemplate(BlockTemplate &&b); // destructor ~BlockTemplate(void) = default; // access S & getSample(void); const S & getSample(void) const; Index getStartRow(void) const; Index getStartCol(void) const; Index getNRow(void) const; Index getNCol(void) const; // assignement operators BlockTemplate & operator=(const S &sample); BlockTemplate & operator=(const S &&sample); private: S &sample_; const Index i_, j_, nRow_, nCol_; }; // block types typedef BlockTemplate>> Block; typedef const BlockTemplate>> ConstBlock; public: // constructors MatSample(void) = default; MatSample(const Index nSample); MatSample(const Index nSample, const Index nRow, const Index nCol); MatSample(ConstBlock &sampleBlock); MatSample(ConstBlock &&sampleBlock); EIGEN_EXPR_CTOR(MatSample, MatSample, Sample>, ArrayExpr) // destructor virtual ~MatSample(void) = default; // assignement operator MatSample & operator=(Block &sampleBlock); MatSample & operator=(Block &&sampleBlock); MatSample & operator=(ConstBlock &sampleBlock); MatSample & operator=(ConstBlock &&sampleBlock); // product/division by scalar operators (not provided by Eigen) static inline Mat scalarMul(const Mat &m, const T &x) { return m*x; } static inline Mat scalarDiv(const Mat &m, const T &x) { return m/x; } MatSample & operator*=(const T &x); MatSample & operator*=(const T &&x); MatSample & operator/=(const T &x); MatSample & operator/=(const T &&x); // block access ConstBlock block(const Index i, const Index j, const Index nRow, const Index nCol) const; Block block(const Index i, const Index j, const Index nRow, const Index nCol); // resize all matrices void resizeMat(const Index nRow, const Index nCol); // covariance matrix Mat covarianceMatrix(const MatSample &sample) const; Mat varianceMatrix(void) const; Mat correlationMatrix(void) const; }; // non-member operators template inline auto operator*(MatSample s, const T &x) ->decltype(SCAL_OP_RETURN(Mul, s, x)) { return SCAL_OP_RETURN(Mul, s, x); } template inline auto operator*(MatSample s, const T &&x) ->decltype(SCAL_OP_RETURN(Mul, s, x)) { return SCAL_OP_RETURN(Mul, s, x); } template inline auto operator*(const T &x, MatSample s)->decltype(s*x) { return s*x; } template inline auto operator*(const T &&x, MatSample s)->decltype(s*x) { return s*x; } template inline auto operator/(MatSample s, const T &x) ->decltype(SCAL_OP_RETURN(Div, s, x)) { return SCAL_OP_RETURN(Div, s, x); } template inline auto operator/(MatSample s, const T &&x) ->decltype(SCAL_OP_RETURN(Div, s, x)) { return SCAL_OP_RETURN(Div, s, x); } // type aliases typedef MatSample DMatSample; typedef MatSample> CMatSample; /****************************************************************************** * Block template implementation * ******************************************************************************/ // constructors //////////////////////////////////////////////////////////////// template template MatSample::BlockTemplate::BlockTemplate(S &sample, const Index i, const Index j, const Index nRow, const Index nCol) : sample_(sample) , i_(i) , j_(j) , nRow_(nRow) , nCol_(nCol) {} template template MatSample::BlockTemplate::BlockTemplate(BlockTemplate &b) : sample_(b.getSample()) , i_(b.getStartRow()) , j_(b.getStartCol()) , nRow_(b.getNRow()) , nCol_(b.getNCol()) {} template template MatSample::BlockTemplate::BlockTemplate(BlockTemplate &&b) : BlockTemplate(b) {} // access ////////////////////////////////////////////////////////////////////// template template S & MatSample::BlockTemplate::getSample(void) { return sample_; } template template const S & MatSample::BlockTemplate::getSample(void) const { return sample_; } template template Index MatSample::BlockTemplate::getStartRow(void) const { return i_; } template template Index MatSample::BlockTemplate::getStartCol(void) const { return j_; } template template Index MatSample::BlockTemplate::getNRow(void) const { return nRow_; } template template Index MatSample::BlockTemplate::getNCol(void) const { return nCol_; } // assignement operators /////////////////////////////////////////////////////// template template typename MatSample::template BlockTemplate & MatSample::BlockTemplate::operator=(const S &sample) { FOR_STAT_ARRAY(sample_, s) { sample_[s].block(i_, j_, nRow_, nCol_) = sample[s]; } return *this; } template template typename MatSample::template BlockTemplate & MatSample::BlockTemplate::operator=(const S &&sample) { *this = sample; return *this; } /****************************************************************************** * DMatSample implementation * ******************************************************************************/ // constructors //////////////////////////////////////////////////////////////// template MatSample::MatSample(const Index nSample) : Sample>(nSample) {} template MatSample::MatSample(const Index nSample, const Index nRow, const Index nCol) : MatSample(nSample) { resizeMat(nRow, nCol); } template MatSample::MatSample(ConstBlock &sampleBlock) : MatSample(sampleBlock.getSample().size(), sampleBlock.getNRow(), sampleBlock.getNCol()) { const MatSample &sample = sampleBlock.getSample(); this->resize(sample.size()); FOR_STAT_ARRAY(*this, s) { (*this)[s] = sample[s].block(sampleBlock.getStartRow(), sampleBlock.getStartCol(), sampleBlock.getNRow(), sampleBlock.getNCol()); } } template MatSample::MatSample(ConstBlock &&sampleBlock) : MatSample(sampleBlock) {} // assignement operator //////////////////////////////////////////////////////// template MatSample & MatSample::operator=(Block &sampleBlock) { MatSample tmp(sampleBlock); this->swap(tmp); return *this; } template MatSample & MatSample::operator=(Block &&sampleBlock) { *this = sampleBlock; return *this; } template MatSample & MatSample::operator=(ConstBlock &sampleBlock) { MatSample tmp(sampleBlock); this->swap(tmp); return *this; } template MatSample & MatSample::operator=(ConstBlock &&sampleBlock) { *this = sampleBlock; return *this; } // product/division by scalar operators (not provided by Eigen) //////////////// template MatSample & MatSample::operator*=(const T &x) { return *this = (*this)*x; } template MatSample & MatSample::operator*=(const T &&x) { return *this = (*this)*x; } template MatSample & MatSample::operator/=(const T &x) { return *this = (*this)/x; } template MatSample & MatSample::operator/=(const T &&x) { return *this = (*this)/x; } // block access //////////////////////////////////////////////////////////////// template typename MatSample::ConstBlock MatSample::block(const Index i, const Index j, const Index nRow, const Index nCol) const { return ConstBlock(*this, i, j, nRow, nCol); } template typename MatSample::Block MatSample::block(const Index i, const Index j, const Index nRow, const Index nCol) { return Block(*this, i, j, nRow, nCol); } // resize all matrices ///////////////////////////////////////////////////////// template void MatSample::resizeMat(const Index nRow, const Index nCol) { FOR_STAT_ARRAY(*this, s) { (*this)[s].resize(nRow, nCol); } } // covariance matrix /////////////////////////////////////////////////////////// template Mat MatSample::covarianceMatrix(const MatSample &sample) const { if (((*this)[central].cols() != 1) or (sample[central].cols() != 1)) { LATAN_ERROR(Size, "samples have more than one column"); } Index n1 = (*this)[central].rows(), n2 = sample[central].rows(); Index nSample = this->size(); Mat tmp1(n1, nSample), tmp2(n2, nSample), res(n1, n2); Mat s1(n1, 1), s2(n2, 1), one(nSample, 1); one.fill(1.); s1.fill(0.); s2.fill(0.); for (unsigned int s = 0; s < nSample; ++s) { s1 += (*this)[s]; tmp1.col(s) = (*this)[s]; } tmp1 -= s1*one.transpose()/static_cast(nSample); for (unsigned int s = 0; s < nSample; ++s) { s2 += sample[s]; tmp2.col(s) = sample[s]; } tmp2 -= s2*one.transpose()/static_cast(nSample); res = tmp1*tmp2.transpose()/static_cast(nSample - 1); return res; } template Mat MatSample::varianceMatrix(void) const { if ((*this)[central].cols() != 1) { LATAN_ERROR(Size, "samples have more than one column"); } Index n1 = (*this)[central].rows(); Index nSample = this->size(); Mat tmp1(n1, nSample), res(n1, n1); Mat s1(n1, 1), one(nSample, 1); one.fill(1.); s1.fill(0.); for (unsigned int s = 0; s < nSample; ++s) { s1 += (*this)[s]; tmp1.col(s) = (*this)[s]; } tmp1 -= s1*one.transpose()/static_cast(nSample); res = tmp1*tmp1.transpose()/static_cast(nSample - 1); return res; } template Mat MatSample::correlationMatrix(void) const { Mat res = varianceMatrix(); Mat invDiag(res.rows(), 1); invDiag = res.diagonal(); invDiag = invDiag.cwiseInverse().cwiseSqrt(); res = (invDiag*invDiag.transpose()).cwiseProduct(res); return res; } END_LATAN_NAMESPACE #endif // Latan_MatSample_hpp_