• API Main Page
  • Documentation
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/linalg.c

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2010 by Matthias Ihrke   *
00003  *   ihrke@nld.ds.mpg.de
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 
00021 #include "linalg.h"
00022 #include "helper.h"
00023 #include <string.h>
00024 #include <math.h>
00025 #include <gsl/gsl_linalg.h>
00026 
00059 gsl_matrix* matrix_to_gsl( Array *in, bool alloc ){
00060   gsl_matrix *out;
00061   if( in->ndim != 2 ){
00062      errprintf("in is not a matrix, ndim=%i\n", in->ndim );
00063   } 
00064   if( alloc ){
00065      out = gsl_matrix_alloc( (size_t)in->size[0], (size_t)in->size[1] );
00066      if( in->dtype==DOUBLE ){ /* faster */
00067         memcpy( out->data, in->data, in->nbytes );
00068      } else { /* slow */
00069         int i,j;
00070         double el;
00071         for( i=0; i<in->size[0]; i++ ){
00072           for( j=0; j<in->size[1]; j++ ){
00073              array_dtype_to_double( &el, array_index2( in, i, j ), in->dtype );
00074              gsl_matrix_set( out, i, j, el );
00075           }
00076         }
00077      }
00078   } else { /* no mallocing */
00079      MALLOC( out, 1, gsl_matrix );
00080      out->size1=(size_t)in->size[0];
00081      out->size2=(size_t)in->size[1];
00082      out->tda=(size_t)in->size[1];
00083      out->data=(double*)in->data;
00084      out->owner=0; /* GSL is not the owner of the data */
00085      out->block=NULL;
00086   }
00087   
00088   return out;
00089 }
00090 
00099 Array* matrix_mean( Array *a, int dim ){
00100   Array *v;
00101   int i,j;
00102   bool ismatrix;
00103   matrix_CHECK( ismatrix, a );
00104   if( !ismatrix ) return NULL;
00105   if( dim!=0 && dim!=1 ){
00106      errprintf("wrong dimension dim=%i, must be in {0,1}\n", dim );
00107      return NULL;
00108   }
00109   double *p;
00110   v = array_new2( DOUBLE, 1, a->size[1-dim] );
00111   for( i=0; i<a->size[1-dim]; i++ ){
00112      p=&array_INDEX1( v, double, i );
00113      *p= 0.0;
00114      for( j=0; j<a->size[dim]; j++ ){
00115         array_INDEX1( v, double, i ) += 
00116           array_INDEX2( a, double, (dim==1)?i:j,(dim==1)?j:i );
00117      }
00118      array_INDEX1( v, double, i ) /= (double)a->size[dim];
00119   }
00120   return v;
00121 }
00122 
00138 Array* matrix_get_row( Array *m, int row, bool alloc ){
00139   Array *rowvec;
00140   bool ismatrix;
00141   matrix_CHECK( ismatrix, m );
00142   if( !ismatrix ) return NULL;  
00143   if( row<0 || row>=m->size[0] ){
00144      errprintf("Index out of bounds: %i/%i\n", row, m->size[0] );
00145      return NULL;
00146   }
00147 
00148   if( !alloc ){
00149      rowvec = array_fromptr2( DOUBLE, 1, array_INDEXMEM2( m, row, 0 ), 
00150                                       m->size[1] );
00151   } else {
00152      rowvec = array_new2( DOUBLE, 1, m->size[1] );
00153      memcpy( rowvec->data, array_INDEXMEM2( m, row, 0 ), 
00154                 m->size[1]*m->dtype_size );
00155   }
00156   return rowvec;
00157 }
00158 
00175 Array* matrix_get_col( Array *m, int col ){
00176   Array *colvec;
00177   int i;
00178   bool ismatrix;
00179   matrix_CHECK( ismatrix, m );
00180   if( !ismatrix ) return NULL;
00181   if( col<0 || col>=m->size[1] ){
00182      errprintf("Index out of bounds: %i/%i\n", col, m->size[1] );
00183      return NULL;
00184   }
00185   colvec = array_new2( DOUBLE, 1, m->size[0] );
00186   for( i=0; i<m->size[0]; i++ ){
00187      array_INDEX1( colvec, double, i )=array_INDEX2(m, double, i, col );
00188   }
00189   return colvec;
00190 }
00191 
00200 Array* matrix_mult( const Array *m1, const Array *m2 ){
00201   Array *out=NULL;
00202   int i,j,k;
00203   bool ismatrix;
00204   matrix_CHECK( ismatrix, m1 ); if( !ismatrix ) return NULL;
00205   matrix_CHECK( ismatrix, m2 ); if( !ismatrix ) return NULL;
00206   if( m1->size[1] != m2->size[0] ){
00207      errprintf("Mismatch in size, cannot calculate matrix product: %i!=%i\n",
00208                   m1->size[1], m2->size[0] );
00209      return NULL;
00210   }
00211 
00212   out = array_new2( DOUBLE, 2, m1->size[0], m2->size[1] );
00213 
00214   double *field;
00215   for( i=0; i<out->size[0]; i++ ){
00216      for( j=0; j<out->size[1]; j++ ){
00217         field=(double*)array_INDEXMEM2( out, i, j );
00218         *field=0.0;
00219         for( k=0; k<m1->size[1]; k++ ){
00220           *field += array_INDEX2( m1, double, i, k )*
00221              array_INDEX2( m2, double, k, j );
00222         }
00223      }
00224   }
00225   
00226   return out;
00227 }
00238 Array* matrix_transpose( Array *m, bool alloc ){
00239   int i,j;
00240   bool ismatrix;
00241   matrix_CHECK( ismatrix, m );
00242   if( !ismatrix ) return NULL;
00243 
00244   Array *out;
00245   out = array_new2( DOUBLE, 2, m->size[1], m->size[0] );
00246   for( i=0; i<m->size[0]; i++ ){
00247      for( j=0; j<m->size[1]; j++ ){
00248         array_INDEX2( out, double, j,i) = array_INDEX2( m, double, i,j);
00249      }
00250   }
00251   if( !alloc ){
00252      memcpy( m->data, out->data, out->nbytes );
00253      array_free( out );
00254      out = m;
00255      double tmp=out->size[0];
00256      out->size[0]=out->size[1];
00257      out->size[1]=tmp;
00258   }
00259   
00260   return out;
00261 }
00262 
00282 Array* matrix_pca( Array *X, Array **var, bool alloc ){
00283   Array *out=NULL;
00284   int i,j;
00285   bool ismatrix;
00286   matrix_CHECK( ismatrix, X );
00287   if( !ismatrix ) return NULL;
00288 
00289   int N,K; /* N observations, K variables */
00290   N = X->size[0];
00291   K = X->size[1];
00292 
00293   Array *tmp = array_copy( X, TRUE );
00294 
00295   /* subtract mean from observations */
00296   Array *mean=matrix_mean( X, 0 ); 
00297   for( i=0; i<N; i++ ){ 
00298      for( j=0; j<K; j++ ){
00299         array_INDEX2( tmp, double, i, j ) -=
00300           array_INDEX1( mean, double, j );
00301      }
00302   }
00303 
00304   array_scale( tmp, 1.0/sqrt((double) N-1 ) );
00305 
00306   gsl_matrix *A=matrix_to_gsl( tmp, TRUE ); /* copy */
00307   gsl_matrix *V=gsl_matrix_alloc( K, K );
00308   gsl_vector *S=gsl_vector_alloc( K );
00309   gsl_vector *workspace=gsl_vector_alloc( K );
00310 
00311   /* A->U, V->V, S->S */
00312   gsl_linalg_SV_decomp( A, V, S, workspace);
00313   gsl_matrix_transpose( V );
00314 
00315   if( var ){
00316      (*var)=array_fromptr2( DOUBLE, 1, S->data, S->size );
00317      S->owner=0; /* transfer ownership to array */
00318      (*var)->free_data=1;
00319      for( i=0; i<array_NUMEL( *var ); i++ ){ 
00320         array_INDEX1( *var, double, i ) = SQR( array_INDEX1( *var, double, i ) );
00321      }
00322   }
00323 
00324   Array *Vp=array_fromptr2( DOUBLE, 2, V->data, V->size1, V->size2 );
00325   matrix_transpose( tmp, FALSE );
00326   out=matrix_mult( Vp, tmp ); /* PCA'd data */
00327   matrix_transpose( out, FALSE );
00328 
00329   if( out->size[0]!=X->size[0] || out->size[1]!=X->size[1] ){
00330      errprintf("Input/Output dimension mismatch: (%i,%i) vs. (%i,%i)\n",
00331                   X->size[0], X->size[1], out->size[0], out->size[1] );
00332   }
00333 
00334   if( !alloc ){ /* write back out->X */
00335      memcpy( X->data, out->data, out->nbytes );
00336      array_free( out );
00337      out = X;
00338   }
00339 
00340   /* clean up */
00341   gsl_matrix_free( A );
00342   gsl_matrix_free( V );
00343   gsl_vector_free( S );
00344   gsl_vector_free( workspace );
00345   array_free( mean );
00346   array_free( Vp );
00347   array_free( tmp );
00348 
00349   return out;
00350 }

Generated on Fri Jun 25 2010 14:10:19 for libeegtools by  doxygen 1.7.0