vl_ihashsum.c
Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2007-12 Andrea Vedaldi and Brian Fulkerson.
00009 All rights reserved.
00010 
00011 This file is part of the VLFeat library and is made available under
00012 the terms of the BSD license (see the COPYING file).
00013 */
00014 
00015 #include <mexutils.h>
00016 #include <vl/generic.h>
00017 
00018 #include <string.h>
00019 
00020 /* hash function */
00021 unsigned int fnv_hash (void const *key, int len)
00022 {
00023   unsigned char const *p = key;
00024   unsigned int h = 2166136261U ;
00025   int i;
00026 
00027   for ( i = 0; i < len; i++ )
00028     h = ( h * 16777619 ) ^ p[i];
00029 
00030   return h;
00031 }
00032 
00033 int
00034 is_null (vl_uint8 const * x, int n)
00035 {
00036   int i ;
00037   for (i = 0 ; i < n ; ++i) {
00038     if (x[i]) return 0 ;
00039   }
00040   return 1 ;
00041 }
00042 
00043 int
00044 is_equal (vl_uint8 const * x, vl_uint8 const * y, int n)
00045 {
00046   int i ;
00047   for (i = 0 ; i < n ; ++i) {
00048     if (x[i] != y[i]) return 0 ;
00049   }
00050   return 1 ;
00051 }
00052 
00053 void
00054 cpy (vl_uint8 * x, vl_uint8 const * y, int n)
00055 {
00056   int i ;
00057   for (i = 0 ; i < n ; ++i){
00058     /*    mexPrintf("cpy:%d %d\n",x[i],y[i]);*/
00059     x[i] = y[i] ;
00060   }
00061 }
00062 
00070 void
00071 mexFunction(int nout, mxArray *out[],
00072             int nin, const mxArray *in[])
00073 {
00074   enum { IN_H, IN_ID, IN_NEXT, IN_K, IN_X } ;
00075   enum { OUT_H, OUT_ID, OUT_NEXT} ;
00076 
00077   mxArray *h_,  *id_, *next_ ;
00078 
00079   vl_uint32 * h ;
00080   vl_uint32 * next ;
00081 
00082   vl_uint8       * id ;
00083   vl_uint8 const * x ;
00084 
00085   unsigned int K, i, N, res, last, ndims ;
00086 
00087   /* -----------------------------------------------------------------
00088    *                                                   Check arguments
00089    * -------------------------------------------------------------- */
00090 
00091   if( nin != 5 ) {
00092     mexErrMsgTxt("Five arguments required") ;
00093   } else if (nout > 3) {
00094     mexErrMsgTxt("At most three output argument.") ;
00095   }
00096 
00097   if(! mxIsNumeric(in[IN_H])   || mxGetClassID(in[IN_H]   )!= mxUINT32_CLASS ||
00098      ! mxIsNumeric(in[IN_NEXT])|| mxGetClassID(in[IN_NEXT])!= mxUINT32_CLASS) {
00099     mexErrMsgTxt("H, NEXT must be UINT32.") ;
00100   }
00101 
00102   if(! mxIsNumeric(in[IN_X])   || mxGetClassID(in[IN_X])   != mxUINT8_CLASS) {
00103     mexErrMsgTxt("X must be UINT8") ;
00104   }
00105 
00106   if (mxGetM(in[IN_H])    != 1 ||
00107       mxGetM(in[IN_NEXT]) != 1) {
00108     mexErrMsgTxt("H, NEXT must be row vectors") ;
00109   }
00110 
00111   if(! mxIsNumeric(in[IN_ID])  || mxGetClassID(in[IN_ID])!= mxUINT8_CLASS) {
00112     mexErrMsgTxt("ID must be UINT8.") ;
00113   }
00114 
00115   ndims = mxGetM(in[IN_ID]) ;
00116   res   = mxGetN(in[IN_H]) ;
00117 
00118   if(res != mxGetN(in[IN_ID]) ||
00119      res != mxGetN(in[IN_NEXT])) {
00120     mexErrMsgTxt("H, ID, NEXT must have the same number of columns") ;
00121   }
00122 
00123   if(ndims != mxGetM(in[IN_X])) {
00124     mexErrMsgTxt("ID and X must havethe same number of rows") ;
00125   }
00126 
00127   if(! vlmxIsPlainScalar(in[IN_K])) {
00128     mexErrMsgTxt("K must be a scalar") ;
00129   }
00130   K     = (unsigned int) *mxGetPr(in[IN_K]) ;
00131 
00132   h_    = mxDuplicateArray(in[IN_H]) ;
00133   id_   = mxDuplicateArray(in[IN_ID]) ;
00134   next_ = mxDuplicateArray(in[IN_NEXT]) ;
00135 
00136   N    = mxGetN(in[IN_X]) ;
00137 
00138   h    = mxGetData(h_   ) ;
00139   id   = mxGetData(id_  ) ;
00140   next = mxGetData(next_) ;
00141   x    = mxGetData(in[IN_X]) ;
00142 
00143   /*
00144      Temporary remove mxArray pointers to these buffer as we will
00145      mxRealloc them and if the user presses Ctrl-C matlab will attempt
00146      to free unvalid memory
00147   */
00148 
00149   mxSetData(h_,    0) ;
00150   mxSetData(id_,   0) ;
00151   mxSetData(next_, 0) ;
00152 
00153   /* search for last occupied slot */
00154   last = res ;
00155   for (i = 0 ; i < res ; ++i) last = VL_MAX(last, next [i]) ;
00156 
00157   /* REMARK: last and next are 1 based */
00158 
00159   if (K > res) {
00160     mexErrMsgTxt("K cannot be larger then the size of H") ;
00161   }
00162   if (last > res) {
00163     mexErrMsgTxt("An element of NEXT is greater than the size of the table") ;
00164   }
00165 
00166   /*  mexPrintf("last:%d\n",last) ;*/
00167 
00168   /* -----------------------------------------------------------------
00169    *                                                            Do job
00170    * -------------------------------------------------------------- */
00171   for (i = 0 ; i < N ; ++i) {
00172     /* hash */
00173     unsigned int h1, h2 ;
00174     unsigned int j, p = 0 ;
00175 
00176     /* cannot hash null labels */
00177     if (is_null (x + i * ndims, ndims)) {
00178       vlmxError(vlmxErrInvalidArgument, "The %d column of X is null.", i+1) ;
00179       continue ;
00180     }
00181 
00182     h1 = fnv_hash(x + i * ndims, ndims) % K ;
00183     h2 = h1 | 0x1 ; /* this needs to be odd */
00184 
00185     /* search first free or matching position */
00186     p = h1 % K ;
00187     for (j = 0 ; j < K ; ++j) {
00188       if (is_null (id + p * ndims,                ndims) ||
00189           is_equal(id + p * ndims, x + i * ndims, ndims)) break ;
00190       h1 += h2 ;
00191       p = h1 % K ;
00192     }
00193 
00194     /* if after scanning the K elements in the hash table an empty/matching
00195       bucket is still
00196        not found, start using next to go into the overflow table */
00197     while (! is_null (id + p * ndims,                ndims) &&
00198            ! is_equal(id + p * ndims, x + i * ndims, ndims)) {
00199       if (next [p] > res) {
00200         mexErrMsgTxt("An element of NEXT is greater than the size of the table") ;
00201       }
00202       /* append */
00203       if (next [p] == 0) {
00204         if (last >= res) {
00205           size_t res_ = res + VL_MAX(res / 2, 2) ;
00206           h    = mxRealloc(h,    res_ * sizeof(vl_uint32)       ) ;
00207           next = mxRealloc(next, res_ * sizeof(vl_uint32)       ) ;
00208           id   = mxRealloc(id,   res_ * sizeof(vl_uint8) * ndims) ;
00209           memset (h    + res,         0, (res_ - res) * sizeof(vl_uint32)       ) ;
00210           memset (next + res,         0, (res_ - res) * sizeof(vl_uint32)       ) ;
00211           memset (id   + res * ndims, 0, (res_ - res) * sizeof(vl_uint8) * ndims) ;
00212           res = res_ ;
00213         }
00214         next [p] = ++ last ;
00215       }
00216       p = next [p] - 1 ;
00217     }
00218 
00219     /* accumulate */
00220     h  [p] += 1 ;
00221     /*    mexPrintf("p %d dims %d i %d N %d\n ", p, ndims, i, N) ;*/
00222     cpy(id + p * ndims, x + i * ndims, ndims) ;
00223   }
00224 
00225   mxSetData(h_,    mxRealloc(h,    last * sizeof(vl_uint32)        )) ;
00226   mxSetData(next_, mxRealloc(next, last * sizeof(vl_uint32)        )) ;
00227   mxSetData(id_,   mxRealloc(id,   last * sizeof(vl_uint8 ) * ndims)) ;
00228 
00229   mxSetN(h_,    last) ;
00230   mxSetN(id_,   last) ;
00231   mxSetN(next_, last) ;
00232 
00233   mxSetM(h_,    1) ;
00234   mxSetM(next_, 1) ;
00235   mxSetM(id_,   ndims) ;
00236 
00237   out[OUT_H]    = h_ ;
00238   out[OUT_ID]   = id_ ;
00239   out[OUT_NEXT] = next_ ;
00240 }


libvlfeat
Author(s): Andrea Vedaldi
autogenerated on Thu Jun 6 2019 20:25:51