/** @brief MATLAB Driver. **/ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { int M,N,S=0,smin=0,K,num_levels=0 ; const int* dimensions ; const double* P_pt ; const double* G_pt ; float* descr_pt ; float* buffer_pt ; float sigma0 ; float magnif = 3.0f ; /* Spatial bin extension factor. */ int NBP = 4 ; /* Number of bins for one spatial direction (even). */ int NBO = 8 ; /* Number of bins for the ortientation. */ int mode = NOSCALESPACE ; int buffer_size=0; enum {IN_G=0,IN_P,IN_SIGMA0,IN_S,IN_SMIN} ; enum {OUT_L=0} ; /* ------------------------------------------------------------------ ** Check the arguments ** --------------------------------------------------------------- */ if (nin < 3) { mexErrMsgTxt("At least three arguments are required") ; } else if (nout > 1) { mexErrMsgTxt("Too many output arguments."); } if( !uIsRealScalar(in[IN_SIGMA0]) ) { mexErrMsgTxt("SIGMA0 should be a real scalar") ; } if(!mxIsDouble(in[IN_G]) || mxGetNumberOfDimensions(in[IN_G]) > 3) { mexErrMsgTxt("G should be a real matrix or 3-D array") ; } sigma0 = (float) *mxGetPr(in[IN_SIGMA0]) ; dimensions = mxGetDimensions(in[IN_G]) ; M = dimensions[0] ; N = dimensions[1] ; G_pt = mxGetPr(in[IN_G]) ; P_pt = mxGetPr(in[IN_P]) ; K = mxGetN(in[IN_P]) ; if( !uIsRealMatrix(in[IN_P],-1,-1)) { mexErrMsgTxt("P should be a real matrix") ; } if ( mxGetM(in[IN_P]) == 4) { /* Standard (scale space) mode */ mode = SCALESPACE ; num_levels = dimensions[2] ; if(nin < 5) { mexErrMsgTxt("Five arguments are required in standard mode") ; } if( !uIsRealScalar(in[IN_S]) ) { mexErrMsgTxt("S should be a real scalar") ; } if( !uIsRealScalar(in[IN_SMIN]) ) { mexErrMsgTxt("SMIN should be a real scalar") ; } if( !uIsRealMatrix(in[IN_P],4,-1)) { mexErrMsgTxt("When the e mode P should be a 4xK matrix.") ; } S = (int)(*mxGetPr(in[IN_S])) ; smin = (int)(*mxGetPr(in[IN_SMIN])) ; } else if ( mxGetM(in[IN_P]) == 3 ) { mode = NOSCALESPACE ; num_levels = 1 ; S = 1 ; smin = 0 ; } else { mexErrMsgTxt("P should be either a 3xK or a 4xK matrix.") ; } /* Parse the property-value pairs */ { char str [80] ; int arg = (mode == SCALESPACE) ? IN_SMIN + 1 : IN_SIGMA0 + 1 ; while(arg < nin) { int k ; if( !uIsString(in[arg],-1) ) { mexErrMsgTxt("The first argument in a property-value pair" " should be a string") ; } mxGetString(in[arg], str, 80) ; #ifdef WINDOWS for(k = 0 ; properties[k] && strcmpi(str, properties[k]) ; ++k) ; #else for(k = 0 ; properties[k] && strcasecmp(str, properties[k]) ; ++k) ; #endif switch (k) { case PROP_NBP: if( !uIsRealScalar(in[arg+1]) ) { mexErrMsgTxt("'NumSpatialBins' should be real scalar") ; } NBP = (int) *mxGetPr(in[arg+1]) ; if( NBP <= 0 || (NBP & 0x1) ) { mexErrMsgTxt("'NumSpatialBins' must be positive and even") ; } break ; case PROP_NBO: if( !uIsRealScalar(in[arg+1]) ) { mexErrMsgTxt("'NumOrientBins' should be a real scalar") ; } NBO = (int) *mxGetPr(in[arg+1]) ; if( NBO <= 0 ) { mexErrMsgTxt("'NumOrientlBins' must be positive") ; } break ; case PROP_MAGNIF: if( !uIsRealScalar(in[arg+1]) ) { mexErrMsgTxt("'Magnif' should be a real scalar") ; } magnif = (float) *mxGetPr(in[arg+1]) ; if( magnif <= 0 ) { mexErrMsgTxt("'Magnif' must be positive") ; } break ; case PROP_UNKNOWN: mexErrMsgTxt("Property unknown.") ; break ; } arg += 2 ; } } /* ----------------------------------------------------------------- * Pre-compute gradient and angles * -------------------------------------------------------------- */ /* Alloc two buffers and make sure their size is multiple of 128 for * better alignment (used also by the Altivec code below.) */ buffer_size = (M*N*num_levels + 0x7f) & (~ 0x7f) ; buffer_pt = (float*) mxMalloc( sizeof(float) * 2 * buffer_size ) ; descr_pt = (float*) mxCalloc( NBP*NBP*NBO*K, sizeof(float) ) ; { /* Offsets to move in the scale space. */ const int yo = 1 ; const int xo = M ; const int so = M*N ; int x,y,s ; #define at(x,y) (*(pt + (x)*xo + (y)*yo)) /* Compute the gradient */ for(s = 0 ; s < num_levels ; ++s) { const double* pt = G_pt + s*so ; for(x = 1 ; x < N-1 ; ++x) { for(y = 1 ; y < M-1 ; ++y) { float Dx = 0.5 * ( at(x+1,y) - at(x-1,y) ) ; float Dy = 0.5 * ( at(x,y+1) - at(x,y-1) ) ; buffer_pt[(x*xo+y*yo+s*so) + 0 ] = Dx ; buffer_pt[(x*xo+y*yo+s*so) + buffer_size] = Dy ; } } } /* Compute angles and modules */ { float* pt = buffer_pt ; int j = 0 ; while (j < N*M*num_levels) { #if defined( MACOSX ) && defined( __ALTIVEC__ ) if( ((unsigned int)pt & 0x7) == 0 && j+3 < N*M*num_levels ) { /* If aligned to 128 bit and there are at least 4 pixels left */ float4 a, b, c, d ; a.vec = vec_ld(0,(vector float*)(pt )) ; b.vec = vec_ld(0,(vector float*)(pt + buffer_size)) ; c.vec = vatan2f(b.vec,a.vec) ; a.x[0] = a.x[0]*a.x[0]+b.x[0]*b.x[0] ; a.x[1] = a.x[1]*a.x[1]+b.x[1]*b.x[1] ; a.x[2] = a.x[2]*a.x[2]+b.x[2]*b.x[2] ; a.x[3] = a.x[3]*a.x[3]+b.x[3]*b.x[3] ; d.vec = vsqrtf(a.vec) ; vec_st(c.vec,0,(vector float*)(pt + buffer_size)) ; vec_st(d.vec,0,(vector float*)(pt )) ; j += 4 ; pt += 4 ; } else { #endif float Dx = *(pt ) ; float Dy = *(pt + buffer_size) ; *(pt ) = sqrtf(Dx*Dx + Dy*Dy) ; if (*pt > 0) *(pt + buffer_size) = atan2f(Dy, Dx) ; else *(pt + buffer_size) = 0 ; j += 1 ; pt += 1 ; #if defined( MACOSX ) && defined( __ALTIVEC__ ) } #endif } } } /* ----------------------------------------------------------------- * Do the job * -------------------------------------------------------------- */ if(K > 0) { int p ; /* Offsets to move in the buffer */ const int yo = 1 ; const int xo = M ; const int so = M*N ; /* Offsets to move in the descriptor. */ /* Use Lowe's convention. */ const int binto = 1 ; const int binyo = NBO * NBP ; const int binxo = NBO ; const int bino = NBO * NBP * NBP ; for(p = 0 ; p < K ; ++p, descr_pt += bino) { /* The SIFT descriptor is a three dimensional histogram of the position * and orientation of the gradient. There are NBP bins for each spatial * dimesions and NBO bins for the orientation dimesion, for a total of * NBP x NBP x NBO bins. * * The support of each spatial bin has an extension of SBP = 3sigma * pixels, where sigma is the scale of the keypoint. Thus all the bins * together have a support SBP x NBP pixels wide . Since weighting and * interpolation of pixel is used, another half bin is needed at both * ends of the extension. Therefore, we need a square window of SBP x * (NBP + 1) pixels. Finally, since the patch can be arbitrarly rotated, * we need to consider a window 2W += sqrt(2) x SBP x (NBP + 1) pixels * wide. */ const float x = (float) *P_pt++ ; const float y = (float) *P_pt++ ; const float s = (float) (mode == SCALESPACE) ? (*P_pt++) : 0.0 ; const float theta0 = (float) *P_pt++ ; const float st0 = sinf(theta0) ; const float ct0 = cosf(theta0) ; const int xi = (int) floor(x+0.5) ; /* Round-off */ const int yi = (int) floor(y+0.5) ; const int si = (int) floor(s+0.5) - smin ; const float sigma = sigma0 * powf(2, s / S) ; const float SBP = magnif * sigma ; const int W = (int) floor( sqrt(2.0) * SBP * (NBP + 1) / 2.0 + 0.5) ; int bin ; int dxi ; int dyi ; const float* pt ; float* dpt ; /* Check that keypoints are within bounds . */ if(xi < 0 || xi > N-1 || yi < 0 || yi > M-1 || ((mode==SCALESPACE) && (si < 0 || si > dimensions[2]-1) ) ) continue ; /* Center the scale space and the descriptor on the current keypoint. * Note that dpt is pointing to the bin of center (SBP/2,SBP/2,0). */ pt = buffer_pt + xi*xo + yi*yo + si*so ; dpt = descr_pt + (NBP/2) * binyo + (NBP/2) * binxo ; #define atd(dbinx,dbiny,dbint) (*(dpt + (dbint)*binto + (dbiny)*binyo + (dbinx)*binxo)) /* * Process each pixel in the window and in the (1,1)-(M-1,N-1) * rectangle. */ for(dxi = max(-W, 1-xi) ; dxi <= min(+W, N-2-xi) ; ++dxi) { for(dyi = max(-W, 1-yi) ; dyi <= min(+W, M-2-yi) ; ++dyi) { /* Compute the gradient. */ float mod = *(pt + dxi*xo + dyi*yo + 0 ) ; float angle = *(pt + dxi*xo + dyi*yo + buffer_size ) ; #ifdef LOWE_COMPATIBLE float theta = fast_mod(-angle + theta0) ; #else float theta = fast_mod(angle - theta0) ; #endif /* Get the fractional displacement. */ float dx = ((float)(xi+dxi)) - x; float dy = ((float)(yi+dyi)) - y; /* Get the displacement normalized w.r.t. the keypoint orientation * and extension. */ float nx = ( ct0 * dx + st0 * dy) / SBP ; float ny = (-st0 * dx + ct0 * dy) / SBP ; float nt = NBO * theta / (2*M_PI) ; /* Get the gaussian weight of the sample. The gaussian window * has a standard deviation of NBP/2. Note that dx and dy are in * the normalized frame, so that -NBP/2 <= dx <= NBP/2. */ const float wsigma = NBP/2 ; float win = expf(-(nx*nx + ny*ny)/(2.0 * wsigma * wsigma)) ; /* The sample will be distributed in 8 adijacient bins. * Now we get the ``lower-left'' bin. */ int binx = fast_floor( nx - 0.5 ) ; int biny = fast_floor( ny - 0.5 ) ; int bint = fast_floor( nt ) ; float rbinx = nx - (binx+0.5) ; float rbiny = ny - (biny+0.5) ; float rbint = nt - bint ; int dbinx ; int dbiny ; int dbint ; /* Distribute the current sample into the 8 adijacient bins. */ for(dbinx = 0 ; dbinx < 2 ; ++dbinx) { for(dbiny = 0 ; dbiny < 2 ; ++dbiny) { for(dbint = 0 ; dbint < 2 ; ++dbint) { if( binx+dbinx >= -(NBP/2) && binx+dbinx < (NBP/2) && biny+dbiny >= -(NBP/2) && biny+dbiny < (NBP/2) ) { float weight = win * mod * fabsf(1 - dbinx - rbinx) * fabsf(1 - dbiny - rbiny) * fabsf(1 - dbint - rbint) ; atd(binx+dbinx, biny+dbiny, (bint+dbint) % NBO) += weight ; } } } } } } { /* Normalize the histogram to L2 unit length. */ normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ; /* Truncate at 0.2. */ for(bin = 0; bin < NBO*NBP*NBP ; ++bin) { if (descr_pt[bin] > 0.2) descr_pt[bin] = 0.2; } /* Normalize again. */ normalize_histogram(descr_pt, descr_pt + NBO*NBP*NBP) ; } } } /* Restore pointer to the beginning of the descriptors. */ descr_pt -= NBO*NBP*NBP*K ; { int k ; double* L_pt ; out[OUT_L] = mxCreateDoubleMatrix(NBP*NBP*NBO, K, mxREAL) ; L_pt = mxGetPr(out[OUT_L]) ; for(k = 0 ; k < NBP*NBP*NBO*K ; ++k) { L_pt[k] = descr_pt[k] ; } } mxFree(descr_pt) ; mxFree(buffer_pt) ; }
/** @brief MEX driver entry point **/ void mexFunction (int nout, mxArray * out[], int nin, const mxArray * in[]) { enum {IN_TREE = 0, IN_DATA, IN_END} ; enum {OUT_ASGN = 0} ; vl_uint8 const *data; int opt ; int next = IN_END ; mxArray const *optarg ; int N = 0 ; int method_type = VL_IKM_LLOYD ; int verb = 0 ; /* ----------------------------------------------------------------- * Check the arguments * -------------------------------------------------------------- */ if (nin < 2) mexErrMsgTxt ("At least two arguments required."); else if (nout > 1) mexErrMsgTxt ("Too many output arguments."); if (mxGetClassID (in[IN_DATA]) != mxUINT8_CLASS) { mexErrMsgTxt ("DATA must be of class UINT8"); } N = mxGetN (in[IN_DATA]); /* n of elements */ data = (vl_uint8 *) mxGetPr (in[IN_DATA]); while ((opt = uNextOption(in, nin, options, &next, &optarg)) >= 0) { char buf [1024] ; switch (opt) { case opt_verbose : ++ verb ; break ; case opt_method : if (!uIsString (optarg, -1)) { mexErrMsgTxt("'Method' must be a string.") ; } if (mxGetString (optarg, buf, sizeof(buf))) { mexErrMsgTxt("Option argument too long.") ; } if (strcmp("lloyd", buf) == 0) { method_type = VL_IKM_LLOYD ; } else if (strcmp("elkan", buf) == 0) { method_type = VL_IKM_ELKAN ; } else { mexErrMsgTxt("Unknown cost type.") ; } break ; default : assert(0) ; break ; } } /* ----------------------------------------------------------------- * Do the job * -------------------------------------------------------------- */ { VlHIKMTree *tree ; vl_uint *ids ; int j; int depth ; tree = matlab_to_hikm (in[IN_TREE], method_type) ; depth = vl_hikm_get_depth (tree) ; if (verb) { mexPrintf("hikmeanspush: ndims: %d K: %d depth: %d\n", vl_hikm_get_ndims (tree), vl_hikm_get_K (tree), depth) ; } out[OUT_ASGN] = mxCreateNumericMatrix (depth, N, mxUINT32_CLASS, mxREAL) ; ids = mxGetData (out[OUT_ASGN]) ; vl_hikm_push (tree, ids, data, N) ; vl_hikm_delete (tree) ; for (j = 0 ; j < N*depth ; j++) ids [j] ++ ; } }
/* driver */ void mexFunction(int nout, mxArray *out[], int nin, const mxArray *in[]) { enum {IN_X=0,IN_C,IN_END} ; enum {OUT_ASGN=0} ; vl_uint* asgn ; vl_ikm_acc* centers ; vl_uint8* data ; int M,N,j,K=0 ; int opt ; int next = IN_END ; mxArray const *optarg ; int method_type = VL_IKM_LLOYD ; int verb = 0 ; VlIKMFilt *ikmf ; VL_USE_MATLAB_ENV ; /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (nin < 2) { mexErrMsgTxt("At least two arguments required.") ; } else if (nout > 2) { mexErrMsgTxt("Too many output arguments.") ; } if(mxGetClassID(in[IN_X]) != mxUINT8_CLASS) { mexErrMsgTxt("X must be of class UINT8") ; } if(mxGetClassID(in[IN_C]) != mxINT32_CLASS) { mexErrMsgTxt("C must be of class INT32") ; } M = mxGetM(in[IN_X]) ; /* n of components */ N = mxGetN(in[IN_X]) ; /* n of elements */ K = mxGetN(in[IN_C]) ; /* n of centers */ if( mxGetM(in[IN_C]) != M ) { mexErrMsgTxt("DATA and CENTERS must have the same number of columns.") ; } while ((opt = uNextOption(in, nin, options, &next, &optarg)) >= 0) { char buf [1024] ; switch (opt) { case opt_verbose : ++ verb ; break ; case opt_method : if (!uIsString (optarg, -1)) { mexErrMsgTxt("'Method' must be a string.") ; } if (mxGetString (optarg, buf, sizeof(buf))) { mexErrMsgTxt("Option argument too long.") ; } if (strcmp("lloyd", buf) == 0) { method_type = VL_IKM_LLOYD ; } else if (strcmp("elkan", buf) == 0) { method_type = VL_IKM_ELKAN ; } else { mexErrMsgTxt("Unknown cost type.") ; } break ; default : assert(0) ; break ; } } /** ----------------------------------------------------------------- ** Check the arguments ** -------------------------------------------------------------- */ if (verb) { char const * method_name = 0 ; switch (method_type) { case VL_IKM_LLOYD: method_name = "Lloyd" ; break ; case VL_IKM_ELKAN: method_name = "Elkan" ; break ; default : assert (0) ; } mexPrintf("ikmeanspush: Method = %s\n", method_name) ; mexPrintf("ikmeanspush: ndata = %d\n", N) ; } out[OUT_ASGN] = mxCreateNumericMatrix (1, N, mxUINT32_CLASS, mxREAL) ; data = (vl_uint8*) mxGetData (in[IN_X]) ; centers = (vl_ikm_acc*) mxGetData (in[IN_C]) ; asgn = (vl_uint*) mxGetData (out[OUT_ASGN]) ; ikmf = vl_ikm_new (method_type) ; vl_ikm_set_verbosity (ikmf, verb) ; vl_ikm_init (ikmf, centers, M, K) ; vl_ikm_push (ikmf, asgn, data, N) ; /* adjust for MATLAB indexing */ for(j = 0 ; j < N ; ++j) ++ asgn[j] ; vl_ikm_delete (ikmf) ; }
void mexFunction (int nout, mxArray ** out, int nin, mxArray const ** in) { SAMPLE sample; /* training sample */ LEARN_PARM learn_parm; KERNEL_PARM kernel_parm; STRUCT_LEARN_PARM struct_parm; STRUCTMODEL structmodel; int alg_type; enum {IN_ARGS=0, IN_SPARM} ; enum {OUT_W=0} ; /* SVM-light is not fully reentrant, so we need to run this patch first */ init_qp_solver() ; verbosity = 0 ; kernel_cache_statistic = 0 ; if (nin != 2) { mexErrMsgTxt("Two arguments required") ; } /* Parse ARGS ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ char arg [1024 + 1] ; int argc ; char ** argv ; if (! uIsString(in[IN_ARGS], -1)) { mexErrMsgTxt("ARGS must be a string") ; } mxGetString(in[IN_ARGS], arg, sizeof(arg) / sizeof(char)) ; arg_split (arg, &argc, &argv) ; svm_struct_learn_api_init(argc+1, argv-1) ; read_input_parameters (argc+1,argv-1, &verbosity, &struct_verbosity, &struct_parm, &learn_parm, &kernel_parm, &alg_type ) ; if (kernel_parm.kernel_type != LINEAR && kernel_parm.kernel_type != CUSTOM) { mexErrMsgTxt ("Only LINEAR or CUSTOM kerneles are supported") ; } /* Parse SPARM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ mxArray const * sparm_array = in [IN_SPARM] ; mxArray const * patterns_array ; mxArray const * labels_array ; mxArray const * kernelFn_array ; int numExamples, ei ; if (! sparm_array) { mexErrMsgTxt("SPARM must be a structure") ; } struct_parm.mex = sparm_array ; patterns_array = mxGetField(sparm_array, 0, "patterns") ; if (! patterns_array || ! mxIsCell(patterns_array)) { mexErrMsgTxt("SPARM.PATTERNS must be a cell array") ; } numExamples = mxGetNumberOfElements(patterns_array) ; labels_array = mxGetField(sparm_array, 0, "labels") ; if (! labels_array || ! mxIsCell(labels_array) || ! mxGetNumberOfElements(labels_array) == numExamples) { mexErrMsgTxt("SPARM.LABELS must be a cell array " "with the same number of elements of " "SPARM.PATTERNS") ; } sample.n = numExamples ; sample.examples = (EXAMPLE *) my_malloc (sizeof(EXAMPLE) * numExamples) ; for (ei = 0 ; ei < numExamples ; ++ ei) { sample.examples[ei].x.mex = mxGetCell(patterns_array, ei) ; sample.examples[ei].y.mex = mxGetCell(labels_array, ei) ; sample.examples[ei].y.isOwner = 0 ; } if (struct_verbosity >= 1) { mexPrintf("There are %d training examples\n", numExamples) ; } kernelFn_array = mxGetField(sparm_array, 0, "kernelFn") ; if (! kernelFn_array && kernel_parm.kernel_type == CUSTOM) { mexErrMsgTxt("SPARM.KERNELFN must be define for CUSTOM kernels") ; } if (kernelFn_array) { MexKernelInfo * info ; if (mxGetClassID(kernelFn_array) != mxFUNCTION_CLASS) { mexErrMsgTxt("SPARM.KERNELFN must be a valid function handle") ; } info = (MexKernelInfo*) kernel_parm.custom ; info -> structParm = sparm_array ; info -> kernelFn = kernelFn_array ; } /* Learning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ switch (alg_type) { case 0: svm_learn_struct(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,NSLACK_ALG) ; break ; case 1: svm_learn_struct(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,NSLACK_SHRINK_ALG); break ; case 2: svm_learn_struct_joint(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,ONESLACK_PRIMAL_ALG); break ; case 3: svm_learn_struct_joint(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,ONESLACK_DUAL_ALG); break ; case 4: svm_learn_struct_joint(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel,ONESLACK_DUAL_CACHE_ALG); break ; case 9: svm_learn_struct_joint_custom(sample,&struct_parm,&learn_parm,&kernel_parm,&structmodel); break ; default: mexErrMsgTxt("Unknown algorithm type") ; } /* Write output ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ /* Warning: The model contains references to the original data 'docs'. If you want to free the original data, and only keep the model, you have to make a deep copy of 'model'. */ mxArray * model_array = newMxArrayEncapsulatingSmodel (&structmodel) ; out[OUT_W] = mxDuplicateArray (model_array) ; destroyMxArrayEncapsulatingSmodel (model_array) ; free_struct_sample (sample) ; free_struct_model (structmodel) ; svm_struct_learn_api_exit () ; free_qp_solver () ; }
void mexFunction (int nout, mxArray * out[], int nin, const mxArray * in[]) { enum {IN_PARENTS = 0, IN_DATA, IN_OPT} ; enum {OUT_TREE} ; vl_uint32 const *parents ; vl_uint32 *tree ; double const *data ; int nnull = 0 ; int histmode = 0 ; int i, P, N ; /* ----------------------------------------------------------------- * Check the arguments * -------------------------------------------------------------- */ if ((nin < 2) || (nin > 3)) { mexErrMsgTxt ("Two or three arguments required.") ; } if (nout > 1) { mexErrMsgTxt ("Too many output arguments.") ; } if (!uIsRealMatrix(in[IN_DATA], -1, -1)) { mexErrMsgTxt ("DATA must be a matrix of DOUBLE"); } if (!uIsVector(in[IN_PARENTS], -1)) { mexErrMsgTxt ("PARENTS must be a vector") ; } if (mxGetClassID(in[IN_PARENTS]) != mxUINT32_CLASS) { mexErrMsgTxt ("PARENTS must be UINT32") ; } N = mxGetNumberOfElements (in[IN_DATA]) ; data = mxGetPr (in[IN_DATA]) ; P = mxGetNumberOfElements (in[IN_PARENTS]) ; parents = mxGetData (in[IN_PARENTS]) ; if (nin > 2) { enum {buflen = 32} ; char buf [buflen] ; if (!uIsString(in[IN_OPT], -1)) { mexErrMsgTxt("OPT must be a string") ; } mxGetString(in[IN_OPT], buf, buflen) ; buf [buflen - 1] = 0 ; if (!uStrICmp("hist", buf)) { mexErrMsgTxt("OPT must be equal to 'hist'") ; } histmode = 1 ; } out[OUT_TREE] = mxCreateNumericMatrix(1, P,mxUINT32_CLASS, mxREAL) ; tree = mxGetData (out[OUT_TREE]) ; /* ----------------------------------------------------------------- * Do the job * -------------------------------------------------------------- */ { char buf [1024] ; vl_uint32 max_node = 0 ; vl_uint32 min_node = 0 ; vl_uint32 last_leaf = 0 ; vl_uint32 root = 0 ; /* exhamine parents for errors and informations */ for (i = 0 ; i < P ; ++i) { vl_uint32 node = parents [i] ; if ((node != 0) & (node != 1)) { max_node = VL_MAX (node, max_node) ; min_node = VL_MIN (node, min_node) ; } /* check no node points outside the tree */ if (node > P) { snprintf(buf, sizeof(buf), "Out of bounds link PARENTS[%d] = %u > %u", i, node, P) ; mexErrMsgTxt (buf) ; } /* check node points to something above him */ if ((node != 0) & (node != 1) & (node < i)) { snprintf(buf, sizeof(buf), "Backward link PARENTS[%d] = %u < %d", i, node, i) ; mexErrMsgTxt (buf) ; } if (node == 0) ++ nnull ; } /* now * * min_node = first node which is not a leaf * max_node = root node * nnull = number of leaves pointing to the null node */ last_leaf = min_node - 1 ; root = max_node ; /* process data */ for (i = 0 ; i < N ; ++i) { int w = 1 ; int x = (int) data [i] ; if (histmode) { w = x ; x = i ; } if ((x < 1) | (x > last_leaf)) { if (histmode) { snprintf(buf, sizeof(buf), "DATA length exceeds number of AIB leaves") ; } else { snprintf(buf, sizeof(buf), "DATA [%d] = %d is not a leaf", i, x) ; } mexErrMsgTxt (buf) ; } while (true) { int x_ = (int) parents [x -1] ; /* mexPrintf("%d : x_=%d, x=%d\n", i, x_, x) ; */ ++ tree [x - 1] ; if ((x_ == x) | (x_ == 0) | (x_ == 1)) break ; x = x_ ; } } } }