| @@ -0,0 +1,374 @@ | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include "svm.h" | |||
| #include "mex.h" | |||
| #ifdef MX_API_VER | |||
| #if MX_API_VER < 0x07030000 | |||
| typedef int mwIndex; | |||
| #endif | |||
| #endif | |||
| #define NUM_OF_RETURN_FIELD 11 | |||
| #define Malloc(type,n) (type *)malloc((n)*sizeof(type)) | |||
| static const char *field_names[] = { | |||
| "Parameters", | |||
| "nr_class", | |||
| "totalSV", | |||
| "rho", | |||
| "Label", | |||
| "sv_indices", | |||
| "ProbA", | |||
| "ProbB", | |||
| "nSV", | |||
| "sv_coef", | |||
| "SVs" | |||
| }; | |||
| const char *model_to_matlab_structure(mxArray *plhs[], int num_of_feature, struct svm_model *model) | |||
| { | |||
| int i, j, n; | |||
| double *ptr; | |||
| mxArray *return_model, **rhs; | |||
| int out_id = 0; | |||
| rhs = (mxArray **)mxMalloc(sizeof(mxArray *)*NUM_OF_RETURN_FIELD); | |||
| // Parameters | |||
| rhs[out_id] = mxCreateDoubleMatrix(5, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| ptr[0] = model->param.svm_type; | |||
| ptr[1] = model->param.kernel_type; | |||
| ptr[2] = model->param.degree; | |||
| ptr[3] = model->param.gamma; | |||
| ptr[4] = model->param.coef0; | |||
| out_id++; | |||
| // nr_class | |||
| rhs[out_id] = mxCreateDoubleMatrix(1, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| ptr[0] = model->nr_class; | |||
| out_id++; | |||
| // total SV | |||
| rhs[out_id] = mxCreateDoubleMatrix(1, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| ptr[0] = model->l; | |||
| out_id++; | |||
| // rho | |||
| n = model->nr_class*(model->nr_class-1)/2; | |||
| rhs[out_id] = mxCreateDoubleMatrix(n, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| for(i = 0; i < n; i++) | |||
| ptr[i] = model->rho[i]; | |||
| out_id++; | |||
| // Label | |||
| if(model->label) | |||
| { | |||
| rhs[out_id] = mxCreateDoubleMatrix(model->nr_class, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| for(i = 0; i < model->nr_class; i++) | |||
| ptr[i] = model->label[i]; | |||
| } | |||
| else | |||
| rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); | |||
| out_id++; | |||
| // sv_indices | |||
| if(model->sv_indices) | |||
| { | |||
| rhs[out_id] = mxCreateDoubleMatrix(model->l, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| for(i = 0; i < model->l; i++) | |||
| ptr[i] = model->sv_indices[i]; | |||
| } | |||
| else | |||
| rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); | |||
| out_id++; | |||
| // probA | |||
| if(model->probA != NULL) | |||
| { | |||
| rhs[out_id] = mxCreateDoubleMatrix(n, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| for(i = 0; i < n; i++) | |||
| ptr[i] = model->probA[i]; | |||
| } | |||
| else | |||
| rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); | |||
| out_id ++; | |||
| // probB | |||
| if(model->probB != NULL) | |||
| { | |||
| rhs[out_id] = mxCreateDoubleMatrix(n, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| for(i = 0; i < n; i++) | |||
| ptr[i] = model->probB[i]; | |||
| } | |||
| else | |||
| rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); | |||
| out_id++; | |||
| // nSV | |||
| if(model->nSV) | |||
| { | |||
| rhs[out_id] = mxCreateDoubleMatrix(model->nr_class, 1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| for(i = 0; i < model->nr_class; i++) | |||
| ptr[i] = model->nSV[i]; | |||
| } | |||
| else | |||
| rhs[out_id] = mxCreateDoubleMatrix(0, 0, mxREAL); | |||
| out_id++; | |||
| // sv_coef | |||
| rhs[out_id] = mxCreateDoubleMatrix(model->l, model->nr_class-1, mxREAL); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| for(i = 0; i < model->nr_class-1; i++) | |||
| for(j = 0; j < model->l; j++) | |||
| ptr[(i*(model->l))+j] = model->sv_coef[i][j]; | |||
| out_id++; | |||
| // SVs | |||
| { | |||
| int ir_index, nonzero_element; | |||
| mwIndex *ir, *jc; | |||
| mxArray *pprhs[1], *pplhs[1]; | |||
| if(model->param.kernel_type == PRECOMPUTED) | |||
| { | |||
| nonzero_element = model->l; | |||
| num_of_feature = 1; | |||
| } | |||
| else | |||
| { | |||
| nonzero_element = 0; | |||
| for(i = 0; i < model->l; i++) { | |||
| j = 0; | |||
| while(model->SV[i][j].index != -1) | |||
| { | |||
| nonzero_element++; | |||
| j++; | |||
| } | |||
| } | |||
| } | |||
| // SV in column, easier accessing | |||
| rhs[out_id] = mxCreateSparse(num_of_feature, model->l, nonzero_element, mxREAL); | |||
| ir = mxGetIr(rhs[out_id]); | |||
| jc = mxGetJc(rhs[out_id]); | |||
| ptr = mxGetPr(rhs[out_id]); | |||
| jc[0] = ir_index = 0; | |||
| for(i = 0;i < model->l; i++) | |||
| { | |||
| if(model->param.kernel_type == PRECOMPUTED) | |||
| { | |||
| // make a (1 x model->l) matrix | |||
| ir[ir_index] = 0; | |||
| ptr[ir_index] = model->SV[i][0].value; | |||
| ir_index++; | |||
| jc[i+1] = jc[i] + 1; | |||
| } | |||
| else | |||
| { | |||
| int x_index = 0; | |||
| while (model->SV[i][x_index].index != -1) | |||
| { | |||
| ir[ir_index] = model->SV[i][x_index].index - 1; | |||
| ptr[ir_index] = model->SV[i][x_index].value; | |||
| ir_index++, x_index++; | |||
| } | |||
| jc[i+1] = jc[i] + x_index; | |||
| } | |||
| } | |||
| // transpose back to SV in row | |||
| pprhs[0] = rhs[out_id]; | |||
| if(mexCallMATLAB(1, pplhs, 1, pprhs, "transpose")) | |||
| return "cannot transpose SV matrix"; | |||
| rhs[out_id] = pplhs[0]; | |||
| out_id++; | |||
| } | |||
| /* Create a struct matrix contains NUM_OF_RETURN_FIELD fields */ | |||
| return_model = mxCreateStructMatrix(1, 1, NUM_OF_RETURN_FIELD, field_names); | |||
| /* Fill struct matrix with input arguments */ | |||
| for(i = 0; i < NUM_OF_RETURN_FIELD; i++) | |||
| mxSetField(return_model,0,field_names[i],mxDuplicateArray(rhs[i])); | |||
| /* return */ | |||
| plhs[0] = return_model; | |||
| mxFree(rhs); | |||
| return NULL; | |||
| } | |||
| struct svm_model *matlab_matrix_to_model(const mxArray *matlab_struct, const char **msg) | |||
| { | |||
| int i, j, n, num_of_fields; | |||
| double *ptr; | |||
| int id = 0; | |||
| struct svm_node *x_space; | |||
| struct svm_model *model; | |||
| mxArray **rhs; | |||
| num_of_fields = mxGetNumberOfFields(matlab_struct); | |||
| if(num_of_fields != NUM_OF_RETURN_FIELD) | |||
| { | |||
| *msg = "number of return field is not correct"; | |||
| return NULL; | |||
| } | |||
| rhs = (mxArray **) mxMalloc(sizeof(mxArray *)*num_of_fields); | |||
| for(i=0;i<num_of_fields;i++) | |||
| rhs[i] = mxGetFieldByNumber(matlab_struct, 0, i); | |||
| model = Malloc(struct svm_model, 1); | |||
| model->rho = NULL; | |||
| model->probA = NULL; | |||
| model->probB = NULL; | |||
| model->label = NULL; | |||
| model->sv_indices = NULL; | |||
| model->nSV = NULL; | |||
| model->free_sv = 1; // XXX | |||
| ptr = mxGetPr(rhs[id]); | |||
| model->param.svm_type = (int)ptr[0]; | |||
| model->param.kernel_type = (int)ptr[1]; | |||
| model->param.degree = (int)ptr[2]; | |||
| model->param.gamma = ptr[3]; | |||
| model->param.coef0 = ptr[4]; | |||
| id++; | |||
| ptr = mxGetPr(rhs[id]); | |||
| model->nr_class = (int)ptr[0]; | |||
| id++; | |||
| ptr = mxGetPr(rhs[id]); | |||
| model->l = (int)ptr[0]; | |||
| id++; | |||
| // rho | |||
| n = model->nr_class * (model->nr_class-1)/2; | |||
| model->rho = (double*) malloc(n*sizeof(double)); | |||
| ptr = mxGetPr(rhs[id]); | |||
| for(i=0;i<n;i++) | |||
| model->rho[i] = ptr[i]; | |||
| id++; | |||
| // label | |||
| if(mxIsEmpty(rhs[id]) == 0) | |||
| { | |||
| model->label = (int*) malloc(model->nr_class*sizeof(int)); | |||
| ptr = mxGetPr(rhs[id]); | |||
| for(i=0;i<model->nr_class;i++) | |||
| model->label[i] = (int)ptr[i]; | |||
| } | |||
| id++; | |||
| // sv_indices | |||
| if(mxIsEmpty(rhs[id]) == 0) | |||
| { | |||
| model->sv_indices = (int*) malloc(model->l*sizeof(int)); | |||
| ptr = mxGetPr(rhs[id]); | |||
| for(i=0;i<model->l;i++) | |||
| model->sv_indices[i] = (int)ptr[i]; | |||
| } | |||
| id++; | |||
| // probA | |||
| if(mxIsEmpty(rhs[id]) == 0) | |||
| { | |||
| model->probA = (double*) malloc(n*sizeof(double)); | |||
| ptr = mxGetPr(rhs[id]); | |||
| for(i=0;i<n;i++) | |||
| model->probA[i] = ptr[i]; | |||
| } | |||
| id++; | |||
| // probB | |||
| if(mxIsEmpty(rhs[id]) == 0) | |||
| { | |||
| model->probB = (double*) malloc(n*sizeof(double)); | |||
| ptr = mxGetPr(rhs[id]); | |||
| for(i=0;i<n;i++) | |||
| model->probB[i] = ptr[i]; | |||
| } | |||
| id++; | |||
| // nSV | |||
| if(mxIsEmpty(rhs[id]) == 0) | |||
| { | |||
| model->nSV = (int*) malloc(model->nr_class*sizeof(int)); | |||
| ptr = mxGetPr(rhs[id]); | |||
| for(i=0;i<model->nr_class;i++) | |||
| model->nSV[i] = (int)ptr[i]; | |||
| } | |||
| id++; | |||
| // sv_coef | |||
| ptr = mxGetPr(rhs[id]); | |||
| model->sv_coef = (double**) malloc((model->nr_class-1)*sizeof(double)); | |||
| for( i=0 ; i< model->nr_class -1 ; i++ ) | |||
| model->sv_coef[i] = (double*) malloc((model->l)*sizeof(double)); | |||
| for(i = 0; i < model->nr_class - 1; i++) | |||
| for(j = 0; j < model->l; j++) | |||
| model->sv_coef[i][j] = ptr[i*(model->l)+j]; | |||
| id++; | |||
| // SV | |||
| { | |||
| int sr, elements; | |||
| int num_samples; | |||
| mwIndex *ir, *jc; | |||
| mxArray *pprhs[1], *pplhs[1]; | |||
| // transpose SV | |||
| pprhs[0] = rhs[id]; | |||
| if(mexCallMATLAB(1, pplhs, 1, pprhs, "transpose")) | |||
| { | |||
| svm_free_and_destroy_model(&model); | |||
| *msg = "cannot transpose SV matrix"; | |||
| return NULL; | |||
| } | |||
| rhs[id] = pplhs[0]; | |||
| sr = (int)mxGetN(rhs[id]); | |||
| ptr = mxGetPr(rhs[id]); | |||
| ir = mxGetIr(rhs[id]); | |||
| jc = mxGetJc(rhs[id]); | |||
| num_samples = (int)mxGetNzmax(rhs[id]); | |||
| elements = num_samples + sr; | |||
| model->SV = (struct svm_node **) malloc(sr * sizeof(struct svm_node *)); | |||
| x_space = (struct svm_node *)malloc(elements * sizeof(struct svm_node)); | |||
| // SV is in column | |||
| for(i=0;i<sr;i++) | |||
| { | |||
| int low = (int)jc[i], high = (int)jc[i+1]; | |||
| int x_index = 0; | |||
| model->SV[i] = &x_space[low+i]; | |||
| for(j=low;j<high;j++) | |||
| { | |||
| model->SV[i][x_index].index = (int)ir[j] + 1; | |||
| model->SV[i][x_index].value = ptr[j]; | |||
| x_index++; | |||
| } | |||
| model->SV[i][x_index].index = -1; | |||
| } | |||
| id++; | |||
| } | |||
| mxFree(rhs); | |||
| return model; | |||
| } | |||