00001
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <mexutils.h>
00016 #include <vl/generic.h>
00017
00018 #include <string.h>
00019
00020
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
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
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
00145
00146
00147
00148
00149 mxSetData(h_, 0) ;
00150 mxSetData(id_, 0) ;
00151 mxSetData(next_, 0) ;
00152
00153
00154 last = res ;
00155 for (i = 0 ; i < res ; ++i) last = VL_MAX(last, next [i]) ;
00156
00157
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
00167
00168
00169
00170
00171 for (i = 0 ; i < N ; ++i) {
00172
00173 unsigned int h1, h2 ;
00174 unsigned int j, p = 0 ;
00175
00176
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 ;
00184
00185
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
00195
00196
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
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
00220 h [p] += 1 ;
00221
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 }