/** * @brief Diagonal of biggest square matrix from top left * * Usage: * @code * Matrix<cxfl> m = rand<double> (2,3); * Matrix<cxfl> d = diag (m); * @endcode * * @param M Matrix * @return Highest non-one dimension */ template <class T> inline static Matrix<T> diag (const Matrix<T>& M) { assert (is2d(M)); size_t sz = (std::min)(size(M,0),size(M,1)); Matrix<T> res (sz,1); for (size_t i = 0; i < sz; ++i) res(i) = M(i,i); return res; }
template<class T> inline static Matrix<T> zpad (const Matrix<T>& a, size_t m, size_t n) { assert(is2d(a)); size_t am = size(a,0), an = size(a,1); assert(am<=m); assert(an<=n); size_t am2 = (m-am)/2, an2 = (n-an)/2; Matrix<T> ret(m,n); for (size_t i = 0; i < an; ++i) std::copy(&a(0,i), &a(0,i)+am, &ret(am2,i+an2)); return ret; }
/** * @brief Matrix matrix multiplication * * Usage: * @code{.cpp} * Matrix<cxfl> m = rand<cxfl> (20,10); * Matrix<cxfl> x = rand<cxfl> (10, 6); * * m = gemm (m, b, 'N', 'C'); * @endcode * * @see BLAS routine xGEMM * * @param A Left factor * @param B Right factor * @param transa (N: A*... | T: A.'*... | C: A'*...) transpose left factor * @param transb (N: ...*B | T: ...*B.' | C: ...*B') transpose right factor * @return Product */ template<class T> inline Matrix<T> gemm (const Matrix<T>& A, const Matrix<T>& B, char transa = 'N', char transb = 'N') { assert (isvec(A)||is2d(A)); assert (isvec(B)||is2d(B)); int aw, ah, bw, bh, m, n, k; T alpha = (T)1., beta = (T)0.; aw = (int)size(A,1); ah = (int)size(A,0), bw = (int)size(B,1), bh = (int)size(B,0); // Check inner dimensions if ( transa == 'N' && transb == 'N' ) assert (aw == bh); else if ( transa == 'N' && (transb == 'T' || transb == 'C')) assert (aw == bw); else if ((transa == 'T' || transa == 'C') && transb == 'N' ) assert (ah == bh); else if ((transa == 'T' || transa == 'C') && (transb == 'T' || transb == 'C')) assert (ah == bw); if (transa == 'N') { m = ah; k = aw; } else if (transa == 'T' || transa == 'C') { m = aw; k = ah; } if (transb == 'N') n = bw; else if (transb == 'T' || transb == 'C') n = bh; Matrix<T> C(m,n); LapackTraits<T>::gemm (transa, transb, m, n, k, alpha, A.Ptr(), ah, B.Ptr(), bh, beta, &C[0], m); return C; }
/** * @brief Hann window * * @param size Side lengths * @param t Scaling factor * @return Window */ template <class T> inline Matrix< std::complex<T> > hannwindow (const Matrix<size_t>& size, const T& t) { size_t dim = size.Dim(0); assert (dim > 1 && dim < 4); Matrix<double> res; if (dim == 1) res = Matrix<double> (size[0], 1); else if (dim == 2) res = Matrix<double> (size[0], size[1]); else res = Matrix<double> (size[0], size[1], size[2]); float h, d; float m[3]; if (isvec(res)) { m[0] = 0.5 * size[0]; m[1] = 0.0; m[2] = 0.0; } else if (is2d(res)) { m[0] = 0.5 * size[0]; m[1] = 0.5 * size[1]; m[2] = 0.0; } else { m[0] = 0.5 * size[0]; m[1] = 0.5 * size[1]; m[2] = 0.5 * size[2]; } res = squeeze(res); for (size_t s = 0; s < res.Dim(2); s++) for (size_t r = 0; r < res.Dim(1); r++) for (size_t c = 0; c < res.Dim(0); c++) { d = pow( (float)pow(((float)c-m[0])/m[0],2) + pow(((float)r-m[1])/m[1],2) + pow(((float)s-m[2])/m[2],2) , (float)0.5); h = (d < 1) ? (0.5 + 0.5 * cos (PI * d)) : 0.0; res(c,r,s) = t * h; } return res; }
/** * @brief Moore penrose pseudo-invert * * Usage: * @code{.cpp} * Matrix<cxfl> m = rand<cxfl> (10,6); * * m = pinv (m); * @endcode * * @see Lapack xGELS * * @param m Matrix * @param trans Transpose m before pinv? * @return Pseudo-inverse */ template<class T> inline Matrix<T> pinv (const Matrix<T>& m, char trans = 'N') { Matrix<T> mm (m); assert (is2d(m)); container<T> work = container<T>(1); int M = size(m, 0); int N = size(m, 1); int nrhs = M; int lda = M; int ldb = MAX(M,N); int lwork = -1; int info = 0; Matrix<T> b = eye<T>(ldb); LapackTraits<T>::gels (trans, M, N, nrhs, mm, lda, b, ldb, work, lwork, info); lwork = (int) TypeTraits<T>::Real(work[0]); work.resize(lwork); LapackTraits<T>::gels (trans, M, N, nrhs, mm, lda, b, ldb, work, lwork, info); if (M > N) for (int i = 0; i < M; i++) memcpy (&b[i*N], &b[i*M], N * sizeof(T)); b = resize (b, N, M); if (info > 0) printf ("ERROR XGELS: the algorithm for computing the SVD failed to converge;\n %i off-diagonal elements " \ "of an intermediate bidiagonal form\n did not converge to zero.", info); else if (info < 0) printf ("ERROR XGELS: the %i-th argument had an illegal value.", -info); return b; }
/** * @brief Cholesky decomposition of positive definite quadratic matrix * * Usage: * @code{.cpp} * Matrix<cxfl> m = rand<cxfl> (20,10); * * m = m.prodt(m); // m*m' Must be positive definite * m = chol (m); * @endcode * * @see LAPACK driver xPOTRF * * @param A Incoming matrix * @param uplo Use upper/lower triangle for decomposition ('U': default/'L') * @return Cholesky decomposition */ template<class T> inline Matrix<T> chol (const Matrix<T>& A, char uplo = 'U') { assert(is2d(A)); Matrix<T> res = A; int info = 0, n = A.Height(); LapackTraits<T>::potrf (uplo, n, &res[0], n, info); if (info > 0) printf ("\nERROR - XPOTRF: the leading minor of order %i is not\n positive definite, and the factorization " \ "could not be\n completed!\n\n", info); else if (info < 0) printf ("\nERROR - XPOTRF: the %i-th argument had an illegal value.\n\n!", -info); for (size_t i = 0; i < n-1; i++) for (size_t j = i+1; j < n; j++) res(j,i) = T(0); return res; }
template<class T, class S> inline boost::tuple<Matrix<T>,Matrix<S>,Matrix<T> > svd2 (const Matrix<T>& IN, char jobz = 'N') { typedef typename LapackTraits<T>::RType T2; boost::tuple<Matrix<T>,Matrix<S>,Matrix<T> > ret; assert (is2d(IN)); assert (jobz == 'N' || jobz == 'S' || jobz == 'A'); Matrix<T> A (IN); int m, n, lwork, info = 0, lda, mn, ldu = 1, ucol = 1, ldvt = 1, vtcol = 1; container<T2> rwork; container<T> work = container<T>(1); m = A.Height(); n = A.Width(); lwork = -1; lda = m; mn = MIN(m,n); if (jobz != 'N') ldu = m; if (jobz == 'A') { ldvt = n; vtcol = (m>=n) ? mn : n; ucol = m; } else if (jobz == 'S') { ucol = mn; ldvt = mn; vtcol = (m>=n) ? mn : n; } Matrix<S>& s = boost::get<1>(ret) = Matrix<S>( mn, IONE); Matrix<T>& U = boost::get<0>(ret) = Matrix<T>( ldu, ucol); Matrix<T>& V = boost::get<2>(ret) = Matrix<T>(ldvt, vtcol); container<int> iwork = container<int>(8 * mn); size_t nr = (typeid(T) == typeid(cxfl) || typeid(T) == typeid(cxdb)) ? ((jobz == 'N') ? mn * 7 : mn * (5 * mn + 7)) : 1; rwork.resize(nr); // Workspace query LapackTraits<T>::gesdd (jobz, m, n, &A[0], lda, &s[0], &U[0], ldu, &V[0], ldvt, &work[0], lwork, &rwork[0], &iwork[0], info); lwork = (int) TypeTraits<T>::Real(work[0]); work.resize(lwork); // SVD LapackTraits<T>::gesdd (jobz, m, n, &A[0], lda, &s[0], &U[0], ldu, &V[0], ldvt, &work[0], lwork, &rwork[0], &iwork[0], info); // Traspose the baby V = !V; V = conj(V); if (info > 0) printf ("\nERROR - XGESDD: The updating process of SBDSDC did not converge.\n\n"); else if (info < 0) printf ("\nERROR - XGESDD: The %i-th argument had an illegal value.\n\n", -info); return ret; }