// Copyright (C) 2013 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_CCA_hh_ #define DLIB_CCA_hh_ #include "cca_abstract.h" #include "../algs.h" #include "../matrix.h" #include "../sparse_vector.h" #include "random_subset_selector.h" namespace dlib { // ---------------------------------------------------------------------------------------- template < typename T > matrix<typename T::type,0,1> compute_correlations ( const matrix_exp<T>& L, const matrix_exp<T>& R ) { DLIB_ASSERT( L.size() > 0 && R.size() > 0 && L.nr() == R.nr(), "\t matrix compute_correlations()" << "\n\t Invalid inputs were given to this function." << "\n\t L.size(): " << L.size() << "\n\t R.size(): " << R.size() << "\n\t L.nr(): " << L.nr() << "\n\t R.nr(): " << R.nr() ); typedef typename T::type type; matrix<type> A, B, C; A = diag(trans(R)*L); B = sqrt(diag(trans(L)*L)); C = sqrt(diag(trans(R)*R)); A = pointwise_multiply(A , reciprocal(pointwise_multiply(B,C))); return A; } // ---------------------------------------------------------------------------------------- template < typename matrix_type, typename T > matrix<T,0,1> impl_cca ( const matrix_type& L, const matrix_type& R, matrix<T>& Ltrans, matrix<T>& Rtrans, unsigned long num_correlations, unsigned long extra_rank, unsigned long q, unsigned long num_output_correlations, double regularization ) { matrix<T> Ul, Vl; matrix<T> Ur, Vr; matrix<T> U, V; matrix<T,0,1> Dr, Dl, D; // Note that we add a few more singular vectors in because it helps improve the // final results if we run this part with a little higher rank than the final SVD. svd_fast(L, Ul, Dl, Vl, num_correlations+extra_rank, q); svd_fast(R, Ur, Dr, Vr, num_correlations+extra_rank, q); // Zero out singular values that are essentially zero so they don't cause numerical // difficulties in the code below. const double eps = std::numeric_limits<T>::epsilon()*std::max(max(Dr),max(Dl))*100; Dl = round_zeros(Dl+regularization,eps); Dr = round_zeros(Dr+regularization,eps); // This matrix is really small so we can do a normal full SVD on it. Note that we // also throw away the columns of Ul and Ur corresponding to zero singular values. svd3(diagm(Dl>0)*tmp(trans(Ul)*Ur)*diagm(Dr>0), U, D, V); // now throw away extra columns of the transformations. We do this in a way // that keeps the directions that have the highest correlations. matrix<T,0,1> temp = D; rsort_columns(U, temp); rsort_columns(V, D); U = colm(U, range(0, num_output_correlations-1)); V = colm(V, range(0, num_output_correlations-1)); D = rowm(D, range(0, num_output_correlations-1)); Ltrans = Vl*inv(diagm(Dl))*U; Rtrans = Vr*inv(diagm(Dr))*V; // Note that the D matrix contains the correlation values for the transformed // vectors. However, when the L and R matrices have rank higher than // num_correlations+extra_rank then the values in D become only approximate. return D; } // ---------------------------------------------------------------------------------------- template <typename T> matrix<T,0,1> cca ( const matrix<T>& L, const matrix<T>& R, matrix<T>& Ltrans, matrix<T>& Rtrans, unsigned long num_correlations, unsigned long extra_rank = 5, unsigned long q = 2, double regularization = 0 ) { DLIB_ASSERT( num_correlations > 0 && L.size() > 0 && R.size() > 0 && L.nr() == R.nr() && regularization >= 0, "\t matrix cca()" << "\n\t Invalid inputs were given to this function." << "\n\t num_correlations: " << num_correlations << "\n\t regularization: " << regularization << "\n\t L.size(): " << L.size() << "\n\t R.size(): " << R.size() << "\n\t L.nr(): " << L.nr() << "\n\t R.nr(): " << R.nr() ); using std::min; const unsigned long n = min(num_correlations, (unsigned long)min(R.nr(),min(L.nc(), R.nc()))); return impl_cca(L,R,Ltrans, Rtrans, num_correlations, extra_rank, q, n, regularization); } // ---------------------------------------------------------------------------------------- template <typename sparse_vector_type, typename T> matrix<T,0,1> cca ( const std::vector<sparse_vector_type>& L, const std::vector<sparse_vector_type>& R, matrix<T>& Ltrans, matrix<T>& Rtrans, unsigned long num_correlations, unsigned long extra_rank = 5, unsigned long q = 2, double regularization = 0 ) { DLIB_ASSERT( num_correlations > 0 && L.size() == R.size() && max_index_plus_one(L) > 0 && max_index_plus_one(R) > 0 && regularization >= 0, "\t matrix cca()" << "\n\t Invalid inputs were given to this function." << "\n\t num_correlations: " << num_correlations << "\n\t regularization: " << regularization << "\n\t L.size(): " << L.size() << "\n\t R.size(): " << R.size() << "\n\t max_index_plus_one(L): " << max_index_plus_one(L) << "\n\t max_index_plus_one(R): " << max_index_plus_one(R) ); using std::min; const unsigned long n = min(max_index_plus_one(L), max_index_plus_one(R)); const unsigned long num_output_correlations = min(num_correlations, std::min<unsigned long>(R.size(),n)); return impl_cca(L,R,Ltrans, Rtrans, num_correlations, extra_rank, q, num_output_correlations, regularization); } // ---------------------------------------------------------------------------------------- template <typename sparse_vector_type, typename Rand_type, typename T> matrix<T,0,1> cca ( const random_subset_selector<sparse_vector_type,Rand_type>& L, const random_subset_selector<sparse_vector_type,Rand_type>& R, matrix<T>& Ltrans, matrix<T>& Rtrans, unsigned long num_correlations, unsigned long extra_rank = 5, unsigned long q = 2 ) { return cca(L.to_std_vector(), R.to_std_vector(), Ltrans, Rtrans, num_correlations, extra_rank, q); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_CCA_hh_