diff -ruN libsvm-2.86/svm-train.c libsvm-2.86-svdd/svm-train.c --- libsvm-2.86/svm-train.c 2006-05-11 10:56:28.000000000 +0200 +++ libsvm-2.86-svdd/svm-train.c 2008-08-05 09:07:07.000000000 +0200 @@ -16,6 +16,7 @@ " 2 -- one-class SVM\n" " 3 -- epsilon-SVR\n" " 4 -- nu-SVR\n" + " 5 -- SVDD\n" "-t kernel_type : set type of kernel function (default 2)\n" " 0 -- linear: u'*v\n" " 1 -- polynomial: (gamma*u'*v + coef0)^degree\n" diff -ruN libsvm-2.86/svm.cpp libsvm-2.86-svdd/svm.cpp --- libsvm-2.86/svm.cpp 2007-10-14 08:29:55.000000000 +0200 +++ libsvm-2.86-svdd/svm.cpp 2008-08-05 11:34:05.000000000 +0200 @@ -1518,6 +1518,38 @@ delete[] zeros; } +static void solve_svdd( + const svm_problem *prob, const svm_parameter *param, + double *alpha, Solver::SolutionInfo* si) +{ + int l = prob->l; + double *linear_term = new double[l]; + schar *ones = new schar[l]; + int i; + + int n = (int)(param->nu*prob->l); // # of alpha's at upper bound + + for(i=0;il) + alpha[n] = param->nu * prob->l - n; + for(i=n+1;ieps, si, param->shrinking); + + delete[] linear_term; + delete[] ones; +} + static void solve_one_class( const svm_problem *prob, const svm_parameter *param, double *alpha, Solver::SolutionInfo* si) @@ -1658,6 +1690,9 @@ case NU_SVR: solve_nu_svr(prob,param,alpha,&si); break; + case SVDD: + solve_svdd(prob,param,alpha,&si); + break; } info("obj = %f, rho = %f\n",si.obj,si.rho); @@ -1714,6 +1749,10 @@ // XXX int free_sv; // 1 if svm_model is created by svm_load_model // 0 if svm_model is created by svm_train + + // for SVDD + double *SVsq; // norm of SVs (SVDD only) + double radius; // radius of hypersphere }; // Platt's binary SVM Probablistic Output: an improvement from Lin et al. @@ -2093,7 +2132,8 @@ if(param->svm_type == ONE_CLASS || param->svm_type == EPSILON_SVR || - param->svm_type == NU_SVR) + param->svm_type == NU_SVR || + param->svm_type == SVDD) { // regression or one-class-svm model->nr_class = 2; @@ -2130,6 +2170,31 @@ ++j; } + if (model->param.svm_type == SVDD) { + + // Compute norm of SVs and find one bounded SV + + j = 0; double min_coef = DBL_MAX; + double *sv_coef = model->sv_coef[0]; + model->SVsq = Malloc(double, nSV); + for(i=0;il;i++) { + model->SVsq[i] = Kernel::k_function(model->SV[i],model->SV[i],model->param); + if (model->sv_coef[0][i] < min_coef) { + min_coef = sv_coef[j]; + j = i; + } + } + + // Determine radius using bounded SV[j] + + double r = model->SVsq[j]; + for(int i=0;il;i++) { + r -= 2 * sv_coef[i] * Kernel::k_function(model->SV[j],model->SV[i],model->param); + r += sv_coef[i] * model->SVsq[i]; + } + model->radius = sqrt(r); + } + free(f.alpha); } else @@ -2480,6 +2545,18 @@ sum -= model->rho[0]; *dec_values = sum; } + else if (model->param.svm_type == SVDD) + { + // Compute distance from center of hypersphere + + double *sv_coef = model->sv_coef[0]; + double d = Kernel::k_function(x,x,model->param); + for(int i=0;il;i++) { + d -= 2 * sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param); + d += sv_coef[i] * model->SVsq[i]; + } + *dec_values = sqrt(d); + } else { int i; @@ -2526,13 +2603,16 @@ { if(model->param.svm_type == ONE_CLASS || model->param.svm_type == EPSILON_SVR || - model->param.svm_type == NU_SVR) + model->param.svm_type == NU_SVR || + model->param.svm_type == SVDD) { double res; svm_predict_values(model, x, &res); if(model->param.svm_type == ONE_CLASS) return (res>0)?1:-1; + else if(model->param.svm_type == SVDD) + return (resradius)?1:-1; else return res; } @@ -2607,7 +2687,7 @@ const char *svm_type_table[] = { - "c_svc","nu_svc","one_class","epsilon_svr","nu_svr",NULL + "c_svc","nu_svc","one_class","epsilon_svr","nu_svr","svdd", NULL }; const char *kernel_type_table[]= @@ -2677,6 +2757,14 @@ fprintf(fp, "\n"); } + if (model->param.svm_type == SVDD) { + fprintf(fp, "SVsq"); + for (int i=0;iSVsq[i]); + fprintf(fp, "\n"); + fprintf(fp, "radius %g\n", model->radius); + } + fprintf(fp, "SV\n"); const double * const *sv_coef = model->sv_coef; const svm_node * const *SV = model->SV; @@ -2811,6 +2899,15 @@ for(int i=0;inSV[i]); } + else if(strcmp(cmd, "SVsq")==0) + { + int n = model->l; + model->SVsq = Malloc(double,n); + for(int i=0;iSVsq[i]); + } + else if(strcmp(cmd,"radius")==0) + fscanf(fp,"%lf",&model->radius); else if(strcmp(cmd,"SV")==0) { while(1) @@ -2897,6 +2994,10 @@ free((void *)(model->SV[0])); for(int i=0;inr_class-1;i++) free(model->sv_coef[i]); + + if (model->param.svm_type == SVDD) + free(model->SVsq); + free(model->SV); free(model->sv_coef); free(model->rho); @@ -2921,6 +3022,7 @@ if(svm_type != C_SVC && svm_type != NU_SVC && svm_type != ONE_CLASS && + svm_type != SVDD && svm_type != EPSILON_SVR && svm_type != NU_SVR) return "unknown svm type"; @@ -2954,6 +3056,7 @@ if(svm_type == NU_SVC || svm_type == ONE_CLASS || + svm_type == SVDD || svm_type == NU_SVR) if(param->nu <= 0 || param->nu > 1) return "nu <= 0 or nu > 1"; @@ -2971,7 +3074,7 @@ return "probability != 0 and probability != 1"; if(param->probability == 1 && - svm_type == ONE_CLASS) + (svm_type == ONE_CLASS || svm_type == SVDD)) return "one-class SVM probability output not supported yet"; diff -ruN libsvm-2.86/svm.h libsvm-2.86-svdd/svm.h --- libsvm-2.86/svm.h 2008-03-04 23:28:21.000000000 +0100 +++ libsvm-2.86-svdd/svm.h 2008-08-05 09:02:44.000000000 +0200 @@ -20,7 +20,7 @@ struct svm_node **x; }; -enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR }; /* svm_type */ +enum { C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR, SVDD }; /* svm_type */ enum { LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED }; /* kernel_type */ struct svm_parameter @@ -38,7 +38,7 @@ int nr_weight; /* for C_SVC */ int *weight_label; /* for C_SVC */ double* weight; /* for C_SVC */ - double nu; /* for NU_SVC, ONE_CLASS, and NU_SVR */ + double nu; /* for NU_SVC, ONE_CLASS, NU_SVR and SVDD */ double p; /* for EPSILON_SVR */ int shrinking; /* use the shrinking heuristics */ int probability; /* do probability estimates */