static void Convolution(const arma::Mat<eT>& input, const arma::Mat<eT>& filter, arma::Mat<eT>& output) { // Use the naive convolution in case the filter isn't two dimensional or the // filter is bigger than the input. if (filter.n_rows > input.n_rows || filter.n_cols > input.n_cols || filter.n_rows == 1 || filter.n_cols == 1) { NaiveConvolution<BorderMode>::Convolution(input, filter, output); } else { arma::Mat<eT> U, V, subOutput; arma::Col<eT> s; arma::svd_econ(U, s, V, filter); // Rank approximation using the singular values calculated with singular // value decomposition of dense filter matrix. const size_t rank = arma::sum(s > (s.n_elem * arma::max(s) * arma::datum::eps)); // Test for separability based on the rank of the kernel and take // advantage of the low rank. if (rank * (filter.n_rows + filter.n_cols) < filter.n_elem) { arma::Mat<eT> subFilter = V.unsafe_col(0) * s(0); NaiveConvolution<BorderMode>::Convolution(input, subFilter, subOutput); subOutput = subOutput.t(); NaiveConvolution<BorderMode>::Convolution(subOutput, U.unsafe_col(0), output); for (size_t r = 1; r < rank; r++) { subFilter = V.unsafe_col(r) * s(r); NaiveConvolution<BorderMode>::Convolution(input, subFilter, subOutput); arma::Mat<eT> temp; subOutput = subOutput.t(); NaiveConvolution<BorderMode>::Convolution(subOutput, U.unsafe_col(r), temp); output += temp; } output = output.t(); } else { FFTConvolution<BorderMode>::Convolution(input, filter, output); } } }
arma::Mat<double> make_covariance_matrix(const arma::Mat<double>& data) { return std::move( (data.t()*data) * (1./(data.n_rows-1)) ); }