LocalTangentSpaceAlignment.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of the GNU General Public License as published by
00004  * the Free Software Foundation; either version 3 of the License, or
00005  * (at your option) any later version.
00006  *
00007  * Written (W) 2011 Sergey Lisitsyn
00008  * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
00009  */
00010 
00011 #include <shogun/preprocessor/LocalTangentSpaceAlignment.h>
00012 #ifdef HAVE_LAPACK
00013 #include <shogun/mathematics/arpack.h>
00014 #include <shogun/mathematics/lapack.h>
00015 #include <shogun/lib/Time.h>
00016 #include <shogun/lib/common.h>
00017 #include <shogun/mathematics/Math.h>
00018 #include <shogun/io/SGIO.h>
00019 #include <shogun/distance/EuclidianDistance.h>
00020 #include <shogun/lib/Signal.h>
00021 
00022 #ifdef HAVE_PTHREAD
00023 #include <pthread.h>
00024 #endif
00025 
00026 using namespace shogun;
00027 
00028 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00029 struct LTSA_THREAD_PARAM
00030 {
00032     int32_t idx_start;
00034     int32_t idx_step;
00036     int32_t idx_stop;
00038     int32_t m_k;
00040     int32_t m_target_dim;
00042     int32_t dim;
00044     int32_t N;
00046     const int32_t* neighborhood_matrix;
00048     float64_t* G_matrix;
00050     float64_t* mean_vector;
00052     float64_t* local_feature_matrix;
00054     const float64_t* feature_matrix;
00056     float64_t* s_values_vector;
00058     float64_t* q_matrix;
00060     float64_t* W_matrix;
00061 #ifdef HAVE_PTHREAD
00062 
00063     PTHREAD_LOCK_T* W_matrix_lock;
00064 #endif
00065 };
00066 #endif
00067 
00068 CLocalTangentSpaceAlignment::CLocalTangentSpaceAlignment() :
00069         CLocallyLinearEmbedding()
00070 {
00071 }
00072 
00073 CLocalTangentSpaceAlignment::~CLocalTangentSpaceAlignment()
00074 {
00075 }
00076 
00077 bool CLocalTangentSpaceAlignment::init(CFeatures* features)
00078 {
00079     return true;
00080 }
00081 
00082 void CLocalTangentSpaceAlignment::cleanup()
00083 {
00084 }
00085 
00086 SGMatrix<float64_t> CLocalTangentSpaceAlignment::apply_to_feature_matrix(CFeatures* features)
00087 {
00088     ASSERT(features);
00089     if (!(features->get_feature_class()==C_SIMPLE &&
00090           features->get_feature_type()==F_DREAL))
00091     {
00092         SG_ERROR("Given features are not of SimpleRealFeatures type.\n");
00093     }
00094 
00095     // shorthand for simplefeatures
00096     CSimpleFeatures<float64_t>* simple_features = (CSimpleFeatures<float64_t>*) features;
00097     SG_REF(features);
00098 
00099     // get dimensionality and number of vectors of data
00100     int32_t dim = simple_features->get_num_features();
00101     if (m_target_dim>dim)
00102         SG_ERROR("Cannot increase dimensionality: target dimensionality is %d while given features dimensionality is %d.\n",
00103                  m_target_dim, dim);
00104 
00105     int32_t N = simple_features->get_num_vectors();
00106     if (m_k>=N)
00107         SG_ERROR("Number of neighbors (%d) should be less than number of objects (%d).\n",
00108              m_k, N);
00109 
00110     // loop variables
00111     int32_t t;
00112 
00113     // compute distance matrix
00114     CDistance* distance = new CEuclidianDistance(simple_features,simple_features);
00115     SG_UNREF(distance->parallel);
00116     distance->parallel = this->parallel;
00117     SGMatrix<int32_t> neighborhood_matrix = get_neighborhood_matrix(distance);
00118 
00119     // init W (weight) matrix
00120     float64_t* W_matrix = SG_CALLOC(float64_t, N*N);
00121 
00122 #ifdef HAVE_PTHREAD
00123     int32_t num_threads = parallel->get_num_threads();
00124     ASSERT(num_threads>0);
00125     // allocate threads and params
00126     pthread_t* threads = SG_MALLOC(pthread_t, num_threads);
00127     LTSA_THREAD_PARAM* parameters = SG_MALLOC(LTSA_THREAD_PARAM, num_threads);
00128 #else
00129     int32_t num_threads = 1;
00130 #endif
00131 
00132     // init matrices and norm factor to be used
00133     float64_t* local_feature_matrix = SG_MALLOC(float64_t, m_k*dim*num_threads);
00134     float64_t* mean_vector = SG_MALLOC(float64_t, dim*num_threads);
00135     float64_t* q_matrix = SG_MALLOC(float64_t, m_k*m_k*num_threads);
00136     float64_t* s_values_vector = SG_MALLOC(float64_t, dim*num_threads);
00137     float64_t* G_matrix = SG_MALLOC(float64_t, m_k*(1+m_target_dim)*num_threads);
00138     
00139     // get feature matrix
00140     SGMatrix<float64_t> feature_matrix = simple_features->get_feature_matrix();
00141 
00142 #ifdef HAVE_PTHREAD
00143     PTHREAD_LOCK_T W_matrix_lock;
00144     pthread_attr_t attr;
00145     PTHREAD_LOCK_INIT(&W_matrix_lock);
00146     pthread_attr_init(&attr);
00147     pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
00148 
00149     for (t=0; t<num_threads; t++)
00150     {
00151         parameters[t].idx_start = t;
00152         parameters[t].idx_step = num_threads;
00153         parameters[t].idx_stop = N;
00154         parameters[t].m_k = m_k;
00155         parameters[t].m_target_dim = m_target_dim;
00156         parameters[t].dim = dim;
00157         parameters[t].N = N;
00158         parameters[t].neighborhood_matrix = neighborhood_matrix.matrix;
00159         parameters[t].G_matrix = G_matrix + (m_k*(1+m_target_dim))*t;
00160         parameters[t].mean_vector = mean_vector + dim*t;
00161         parameters[t].local_feature_matrix = local_feature_matrix + (m_k*dim)*t;
00162         parameters[t].feature_matrix = feature_matrix.matrix;
00163         parameters[t].s_values_vector = s_values_vector + dim*t;
00164         parameters[t].q_matrix = q_matrix + (m_k*m_k)*t;
00165         parameters[t].W_matrix = W_matrix;
00166         parameters[t].W_matrix_lock = &W_matrix_lock;
00167         pthread_create(&threads[t], &attr, run_ltsa_thread, (void*)&parameters[t]);
00168     }
00169     for (t=0; t<num_threads; t++)
00170         pthread_join(threads[t], NULL);
00171     PTHREAD_LOCK_DESTROY(&W_matrix_lock);
00172     SG_FREE(parameters);
00173     SG_FREE(threads);
00174 #else
00175     LTSA_THREAD_PARAM single_thread_param;
00176     single_thread_param.idx_start = 0;
00177     single_thread_param.idx_step = 1;
00178     single_thread_param.idx_stop = N;
00179     single_thread_param.m_k = m_k;
00180     single_thread_param.m_target_dim = m_target_dim;
00181     single_thread_param.dim = dim;
00182     single_thread_param.N = N;
00183     single_thread_param.neighborhood_matrix = neighborhood_matrix.matrix;
00184     single_thread_param.G_matrix = G_matrix;
00185     single_thread_param.mean_vector = mean_vector;
00186     single_thread_param.local_feature_matrix = local_feature_matrix;
00187     single_thread_param.feature_matrix = feature_matrix.matrix;
00188     single_thread_param.s_values_vector = s_values_vector;
00189     single_thread_param.q_matrix = q_matrix;
00190     single_thread_param.W_matrix = W_matrix;
00191     run_ltsa_thread((void*)&single_thread_param);
00192 #endif
00193 
00194     // clean
00195     SG_FREE(G_matrix);
00196     SG_FREE(s_values_vector);
00197     SG_FREE(mean_vector);
00198     neighborhood_matrix.destroy_matrix();
00199     SG_FREE(local_feature_matrix);
00200     SG_FREE(q_matrix);
00201 
00202     // finally construct embedding
00203     SGMatrix<float64_t> W_sgmatrix(W_matrix,N,N);
00204     simple_features->set_feature_matrix(find_null_space(W_sgmatrix,m_target_dim,false));
00205     W_sgmatrix.destroy_matrix();
00206 
00207     SG_UNREF(features);
00208     return simple_features->get_feature_matrix();
00209 }
00210 
00211 SGVector<float64_t> CLocalTangentSpaceAlignment::apply_to_feature_vector(SGVector<float64_t> vector)
00212 {
00213     SG_NOTIMPLEMENTED;
00214     return vector;
00215 }
00216 
00217 void* CLocalTangentSpaceAlignment::run_ltsa_thread(void* p)
00218 {
00219     LTSA_THREAD_PARAM* parameters = (LTSA_THREAD_PARAM*)p;
00220     int32_t idx_start = parameters->idx_start;
00221     int32_t idx_step = parameters->idx_step;
00222     int32_t idx_stop = parameters->idx_stop;
00223     int32_t m_k = parameters->m_k;
00224     int32_t m_target_dim = parameters->m_target_dim;
00225     int32_t dim = parameters->dim;
00226     int32_t N = parameters->N;
00227     const int32_t* neighborhood_matrix = parameters->neighborhood_matrix;
00228     float64_t* G_matrix = parameters->G_matrix;
00229     float64_t* mean_vector = parameters->mean_vector;
00230     float64_t* local_feature_matrix = parameters->local_feature_matrix;
00231     const float64_t* feature_matrix = parameters->feature_matrix;
00232     float64_t* s_values_vector = parameters->s_values_vector;
00233     float64_t* q_matrix = parameters->q_matrix;
00234     float64_t* W_matrix = parameters->W_matrix;
00235 #ifdef HAVE_PTHREAD
00236     PTHREAD_LOCK_T* W_matrix_lock = parameters->W_matrix_lock;
00237 #endif
00238 
00239     int i,j,k;
00240 
00241     for (i=idx_start; i<idx_stop; i+=idx_step)
00242     {
00243         for (j=0; j<m_k; j++)
00244             G_matrix[j] = 1.0/CMath::sqrt((float64_t)m_k);
00245 
00246         // fill mean vector with zeros
00247         for (j=0; j<dim; j++)
00248             mean_vector[j] = 0.0;
00249 
00250         // compute local feature matrix containing neighbors of i-th vector
00251         for (j=0; j<m_k; j++)
00252         {
00253             for (k=0; k<dim; k++)
00254             {
00255                 local_feature_matrix[j*dim+k] = feature_matrix[neighborhood_matrix[j*N+i]*dim+k];
00256                 mean_vector[k] += local_feature_matrix[j*dim+k];
00257             }
00258         }
00259 
00260         // compute mean
00261         for (j=0; j<dim; j++)
00262             mean_vector[j] /= m_k;
00263 
00264         // center feature vectors by mean
00265         for (j=0; j<m_k; j++)
00266         {
00267             for (k=0; k<dim; k++)
00268                 local_feature_matrix[j*dim+k] -= mean_vector[k];
00269         }
00270 
00271         int32_t info = 0;
00272         // find right eigenvectors of local_feature_matrix
00273         wrap_dgesvd('N','O', dim,m_k,local_feature_matrix,dim,
00274                              s_values_vector,
00275                              NULL,1, NULL,1, &info);
00276         ASSERT(info==0);
00277         
00278         for (j=0; j<m_target_dim; j++)
00279         {
00280             for (k=0; k<m_k; k++)
00281                 G_matrix[(j+1)*m_k+k] = local_feature_matrix[k*dim+j];
00282         }
00283 
00284         // compute GG'
00285         cblas_dgemm(CblasColMajor,CblasNoTrans,CblasTrans,
00286                     m_k,m_k,1+m_target_dim,
00287                     1.0,G_matrix,m_k,
00288                         G_matrix,m_k,
00289                     0.0,q_matrix,m_k);
00290         
00291         // W[neighbors of i, neighbors of i] = I - GG'
00292 #ifdef HAVE_PTHREAD
00293         PTHREAD_LOCK(W_matrix_lock);
00294 #endif
00295         for (j=0; j<m_k; j++)
00296         {
00297             W_matrix[N*neighborhood_matrix[j*N+i]+neighborhood_matrix[j*N+i]] += 1.0;
00298 
00299             for (k=0; k<m_k; k++)
00300                 W_matrix[N*neighborhood_matrix[k*N+i]+neighborhood_matrix[j*N+i]] -= q_matrix[j*m_k+k];
00301         }
00302 #ifdef HAVE_PTHREAD
00303         PTHREAD_UNLOCK(W_matrix_lock);
00304 #endif
00305     }
00306     return NULL;
00307 }
00308 
00309 #endif /* HAVE_LAPACK */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

SHOGUN Machine Learning Toolbox - Documentation