changeset 12589:06a805605e9a octave-forge

[nan] upgrade libsvm to v3.12
author schloegl
date Sun, 12 Apr 2015 14:37:46 +0000
parents 3f24658504ab
children fae7c16ebcb4
files extra/NaN/src/svm.cpp extra/NaN/src/svm.h extra/NaN/src/svm_model_matlab.c extra/NaN/src/svmpredict_mex.cpp extra/NaN/src/svmtrain_mex.cpp
diffstat 5 files changed, 198 insertions(+), 154 deletions(-) [+]
line wrap: on
line diff
--- a/extra/NaN/src/svm.cpp	Thu Apr 09 17:43:15 2015 +0000
+++ b/extra/NaN/src/svm.cpp	Sun Apr 12 14:37:46 2015 +0000
@@ -1,13 +1,11 @@
 /*
 
-
-$Id$
-Copyright (c) 2000-2009 Chih-Chung Chang and Chih-Jen Lin
-Copyright (c) 2010 Alois Schloegl <alois.schloegl@gmail.com>
+Copyright (c) 2000-2012 Chih-Chung Chang and Chih-Jen Lin
+Copyright (c) 2010,2011,2015 Alois Schloegl <alois.schloegl@ist.ac.at>
 This function is part of the NaN-toolbox
 http://pub.ist.ac.at/~schloegl/matlab/NaN/
 
-This code was extracted from libsvm-mat-2.9-1 in Jan 2010 and 
+This code was extracted from libsvm-3.12 in Apr 2015 and 
 modified for the use with Octave 
 
 This program is free software; you can redistribute it and/or modify
@@ -32,6 +30,8 @@
 #include <float.h>
 #include <string.h>
 #include <stdarg.h>
+#include <limits.h>
+#include <locale.h>
 #include "svm.h"
 
 int libsvm_version = LIBSVM_VERSION;
@@ -69,7 +69,7 @@
 	fputs(s,stdout);
 	fflush(stdout);
 }
-void (*svm_print_string) (const char *) = &print_string_stdout;
+static void (*svm_print_string) (const char *) = &print_string_stdout;
 #if 1
 static void info(const char *fmt,...)
 {
@@ -220,7 +220,7 @@
 class QMatrix {
 public:
 	virtual Qfloat *get_Q(int column, int len) const = 0;
-	virtual Qfloat *get_QD() const = 0;
+	virtual double *get_QD() const = 0;
 	virtual void swap_index(int i, int j) const = 0;
 	virtual ~QMatrix() {}
 };
@@ -233,7 +233,7 @@
 	static double k_function(const svm_node *x, const svm_node *y,
 				 const svm_parameter& param);
 	virtual Qfloat *get_Q(int column, int len) const = 0;
-	virtual Qfloat *get_QD() const = 0;
+	virtual double *get_QD() const = 0;
 	virtual void swap_index(int i, int j) const	// no so const...
 	{
 		swap(x[i],x[j]);
@@ -440,7 +440,7 @@
 	char *alpha_status;	// LOWER_BOUND, UPPER_BOUND, FREE
 	double *alpha;
 	const QMatrix *Q;
-	const Qfloat *QD;
+	const double *QD;
 	double eps;
 	double Cp,Cn;
 	double *p;
@@ -502,7 +502,7 @@
 			nr_free++;
 
 	if(2*nr_free < active_size)
-		info("\nWarning: using -h 0 may be faster\n");
+		info("\nWARNING: using -h 0 may be faster\n");
 
 	if (nr_free*l > 2*active_size*(l-active_size))
 	{
@@ -584,9 +584,10 @@
 	// optimization step
 
 	int iter = 0;
+	int max_iter = max(10000000, l>INT_MAX/100 ? INT_MAX : 100*l);
 	int counter = min(l,1000)+1;
-
-	while(1)
+	
+	while(iter < max_iter)
 	{
 		// show progress and do shrinking
 
@@ -626,7 +627,7 @@
 
 		if(y[i]!=y[j])
 		{
-			double quad_coef = Q_i[i]+Q_j[j]+2*Q_i[j];
+			double quad_coef = QD[i]+QD[j]+2*Q_i[j];
 			if (quad_coef <= 0)
 				quad_coef = TAU;
 			double delta = (-G[i]-G[j])/quad_coef;
@@ -669,7 +670,7 @@
 		}
 		else
 		{
-			double quad_coef = Q_i[i]+Q_j[j]-2*Q_i[j];
+			double quad_coef = QD[i]+QD[j]-2*Q_i[j];
 			if (quad_coef <= 0)
 				quad_coef = TAU;
 			double delta = (G[i]-G[j])/quad_coef;
@@ -753,6 +754,18 @@
 		}
 	}
 
+	if(iter >= max_iter)
+	{
+		if(active_size < l)
+		{
+			// reconstruct the whole gradient to calculate objective value
+			reconstruct_gradient();
+			active_size = l;
+			info("*");
+		}
+		info("\nWARNING: reaching max number of iterations");
+	}
+
 	// calculate rho
 
 	si->rho = calculate_rho();
@@ -847,7 +860,7 @@
 				if (grad_diff > 0)
 				{
 					double obj_diff; 
-					double quad_coef=Q_i[i]+QD[j]-2.0*y[i]*Q_i[j];
+					double quad_coef = QD[i]+QD[j]-2.0*y[i]*Q_i[j];
 					if (quad_coef > 0)
 						obj_diff = -(grad_diff*grad_diff)/quad_coef;
 					else
@@ -871,7 +884,7 @@
 				if (grad_diff > 0)
 				{
 					double obj_diff; 
-					double quad_coef=Q_i[i]+QD[j]+2.0*y[i]*Q_i[j];
+					double quad_coef = QD[i]+QD[j]+2.0*y[i]*Q_i[j];
 					if (quad_coef > 0)
 						obj_diff = -(grad_diff*grad_diff)/quad_coef;
 					else
@@ -1099,7 +1112,7 @@
 				if (grad_diff > 0)
 				{
 					double obj_diff; 
-					double quad_coef = Q_ip[ip]+QD[j]-2*Q_ip[j];
+					double quad_coef = QD[ip]+QD[j]-2*Q_ip[j];
 					if (quad_coef > 0)
 						obj_diff = -(grad_diff*grad_diff)/quad_coef;
 					else
@@ -1123,7 +1136,7 @@
 				if (grad_diff > 0)
 				{
 					double obj_diff; 
-					double quad_coef = Q_in[in]+QD[j]-2*Q_in[j];
+					double quad_coef = QD[in]+QD[j]-2*Q_in[j];
 					if (quad_coef > 0)
 						obj_diff = -(grad_diff*grad_diff)/quad_coef;
 					else
@@ -1284,9 +1297,9 @@
 	{
 		clone(y,y_,prob.l);
 		cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20)));
-		QD = new Qfloat[prob.l];
+		QD = new double[prob.l];
 		for(int i=0;i<prob.l;i++)
-			QD[i]= (Qfloat)(this->*kernel_function)(i,i);
+			QD[i] = (this->*kernel_function)(i,i);
 	}
 	
 	Qfloat *get_Q(int i, int len) const
@@ -1301,7 +1314,7 @@
 		return data;
 	}
 
-	Qfloat *get_QD() const
+	double *get_QD() const
 	{
 		return QD;
 	}
@@ -1323,7 +1336,7 @@
 private:
 	schar *y;
 	Cache *cache;
-	Qfloat *QD;
+	double *QD;
 };
 
 class ONE_CLASS_Q: public Kernel
@@ -1333,9 +1346,9 @@
 	:Kernel(prob.l, prob.x, param)
 	{
 		cache = new Cache(prob.l,(long int)(param.cache_size*(1<<20)));
-		QD = new Qfloat[prob.l];
+		QD = new double[prob.l];
 		for(int i=0;i<prob.l;i++)
-			QD[i]= (Qfloat)(this->*kernel_function)(i,i);
+			QD[i] = (this->*kernel_function)(i,i);
 	}
 	
 	Qfloat *get_Q(int i, int len) const
@@ -1350,7 +1363,7 @@
 		return data;
 	}
 
-	Qfloat *get_QD() const
+	double *get_QD() const
 	{
 		return QD;
 	}
@@ -1369,7 +1382,7 @@
 	}
 private:
 	Cache *cache;
-	Qfloat *QD;
+	double *QD;
 };
 
 class SVR_Q: public Kernel
@@ -1380,7 +1393,7 @@
 	{
 		l = prob.l;
 		cache = new Cache(l,(long int)(param.cache_size*(1<<20)));
-		QD = new Qfloat[2*l];
+		QD = new double[2*l];
 		sign = new schar[2*l];
 		index = new int[2*l];
 		for(int k=0;k<l;k++)
@@ -1389,8 +1402,8 @@
 			sign[k+l] = -1;
 			index[k] = k;
 			index[k+l] = k;
-			QD[k]= (Qfloat)(this->*kernel_function)(k,k);
-			QD[k+l]=QD[k];
+			QD[k] = (this->*kernel_function)(k,k);
+			QD[k+l] = QD[k];
 		}
 		buffer[0] = new Qfloat[2*l];
 		buffer[1] = new Qfloat[2*l];
@@ -1423,7 +1436,7 @@
 		return buf;
 	}
 
-	Qfloat *get_QD() const
+	double *get_QD() const
 	{
 		return QD;
 	}
@@ -1444,7 +1457,7 @@
 	int *index;
 	mutable int next_buffer;
 	Qfloat *buffer[2];
-	Qfloat *QD;
+	double *QD;
 };
 
 //
@@ -1464,7 +1477,7 @@
 	{
 		alpha[i] = 0;
 		minus_ones[i] = -1;
-		if(prob->y[i] > 0) y[i] = +1; else y[i]=-1;
+		if(prob->y[i] > 0) y[i] = +1; else y[i] = -1;
 	}
 
 	Solver s;
@@ -1714,31 +1727,6 @@
 	return f;
 }
 
-//
-// svm_model
-//
-/* 
-struct svm_model
-{
-	svm_parameter param;	// parameter
-	int nr_class;		// number of classes, = 2 in regression/one class svm
-	int l;			// total #SV
-	svm_node **SV;		// SVs (SV[l])
-	double **sv_coef;	// coefficients for SVs in decision functions (sv_coef[k-1][l])
-	double *rho;		// constants in decision functions (rho[k*(k-1)/2])
-	double *probA;		// pariwise probability information
-	double *probB;
-
-	// for classification only
-
-	int *label;		// label of each class (label[k])
-	int *nSV;		// number of SVs for each class (nSV[k])
-				// nSV[0] + nSV[1] + ... + nSV[k-1] = l
-	// XXX
-	int free_sv;		// 1 if svm_model is created by svm_load_model
-				// 0 if svm_model is created by svm_train
-};
-*/ 
 // Platt's binary SVM Probablistic Output: an improvement from Lin et al.
 static void sigmoid_train(
 	int l, const double *dec_values, const double *labels, 
@@ -1856,6 +1844,7 @@
 static double sigmoid_predict(double decision_value, double A, double B)
 {
 	double fApB = decision_value*A+B;
+	// 1-p used later; avoid catastrophic cancellation
 	if (fApB >= 0)
 		return exp(-fApB)/(1.0+exp(-fApB));
 	else
@@ -2002,7 +1991,7 @@
 				// ensure +1 -1 order; reason not using CV subroutine
 				dec_values[perm[j]] *= submodel->label[0];
 			}		
-			svm_destroy_model(submodel);
+			svm_free_and_destroy_model(&submodel);
 			svm_destroy_param(&subparam);
 		}
 		free(subprob.x);
@@ -2166,7 +2155,10 @@
 		int *perm = Malloc(int,l);
 
 		// group training data of the same class
-		svm_group_classes(prob,&nr_class,&label,&start,&count,perm);		
+		svm_group_classes(prob,&nr_class,&label,&start,&count,perm);
+		if(nr_class == 1) 
+			info("WARNING: training data in only one class. See README for details.\n");
+		
 		svm_node **x = Malloc(svm_node *,l);
 		int i;
 		for(i=0;i<l;i++)
@@ -2184,7 +2176,7 @@
 				if(param->weight_label[i] == label[j])
 					break;
 			if(j == nr_class)
-				fprintf(stderr,"warning: class label %d specified in weight is not found\n", param->weight_label[i]);
+				fprintf(stderr,"WARNING: class label %d specified in weight is not found\n", param->weight_label[i]);
 			else
 				weighted_C[j] *= param->weight[i];
 		}
@@ -2452,7 +2444,7 @@
 		else
 			for(j=begin;j<end;j++)
 				target[perm[j]] = svm_predict(submodel,prob->x[perm[j]]);
-		svm_destroy_model(submodel);
+		svm_free_and_destroy_model(&submodel);
 		free(subprob.x);
 		free(subprob.y);
 	}		
@@ -2490,22 +2482,27 @@
 	}
 }
 
-void svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values)
+double svm_predict_values(const svm_model *model, const svm_node *x, double* dec_values)
 {
+	int i;
 	if(model->param.svm_type == ONE_CLASS ||
 	   model->param.svm_type == EPSILON_SVR ||
 	   model->param.svm_type == NU_SVR)
 	{
 		double *sv_coef = model->sv_coef[0];
 		double sum = 0;
-		for(int i=0;i<model->l;i++)
+		for(i=0;i<model->l;i++)
 			sum += sv_coef[i] * Kernel::k_function(x,model->SV[i],model->param);
 		sum -= model->rho[0];
 		*dec_values = sum;
+
+		if(model->param.svm_type == ONE_CLASS)
+			return (sum>0)?1:-1;
+		else
+			return sum;
 	}
 	else
 	{
-		int i;
 		int nr_class = model->nr_class;
 		int l = model->l;
 		
@@ -2518,6 +2515,10 @@
 		for(i=1;i<nr_class;i++)
 			start[i] = start[i-1]+model->nSV[i-1];
 
+		int *vote = Malloc(int,nr_class);
+		for(i=0;i<nr_class;i++)
+			vote[i] = 0;
+
 		int p=0;
 		for(i=0;i<nr_class;i++)
 			for(int j=i+1;j<nr_class;j++)
@@ -2537,58 +2538,41 @@
 					sum += coef2[sj+k] * kvalue[sj+k];
 				sum -= model->rho[p];
 				dec_values[p] = sum;
-				p++;
-			}
 
-		free(kvalue);
-		free(start);
-	}
-}
-
-double svm_predict(const svm_model *model, const svm_node *x)
-{
-	if(model->param.svm_type == ONE_CLASS ||
-	   model->param.svm_type == EPSILON_SVR ||
-	   model->param.svm_type == NU_SVR)
-	{
-		double res;
-		svm_predict_values(model, x, &res);
-		
-		if(model->param.svm_type == ONE_CLASS)
-			return (res>0)?1:-1;
-		else
-			return res;
-	}
-	else
-	{
-		int i;
-		int nr_class = model->nr_class;
-		double *dec_values = Malloc(double, nr_class*(nr_class-1)/2);
-		svm_predict_values(model, x, dec_values);
-
-		int *vote = Malloc(int,nr_class);
-		for(i=0;i<nr_class;i++)
-			vote[i] = 0;
-		int pos=0;
-		for(i=0;i<nr_class;i++)
-			for(int j=i+1;j<nr_class;j++)
-			{
-				if(dec_values[pos++] > 0)
+				if(dec_values[p] > 0)
 					++vote[i];
 				else
 					++vote[j];
+				p++;
 			}
 
 		int vote_max_idx = 0;
 		for(i=1;i<nr_class;i++)
 			if(vote[i] > vote[vote_max_idx])
 				vote_max_idx = i;
+
+		free(kvalue);
+		free(start);
 		free(vote);
-		free(dec_values);
 		return model->label[vote_max_idx];
 	}
 }
 
+double svm_predict(const svm_model *model, const svm_node *x)
+{
+	int nr_class = model->nr_class;
+	double *dec_values;
+	if(model->param.svm_type == ONE_CLASS ||
+	   model->param.svm_type == EPSILON_SVR ||
+	   model->param.svm_type == NU_SVR)
+		dec_values = Malloc(double, 1);
+	else 
+		dec_values = Malloc(double, nr_class*(nr_class-1)/2);
+	double pred_result = svm_predict_values(model, x, dec_values);
+	free(dec_values);
+	return pred_result;
+}
+
 double svm_predict_probability(
 	const svm_model *model, const svm_node *x, double *prob_estimates)
 {
@@ -2643,6 +2627,9 @@
 	FILE *fp = fopen(model_file_name,"w");
 	if(fp==NULL) return -1;
 
+	char *old_locale = strdup(setlocale(LC_ALL, NULL));
+	setlocale(LC_ALL, "C");
+
 	const svm_parameter& param = model->param;
 
 	fprintf(fp,"svm_type %s\n", svm_type_table[param.svm_type]);
@@ -2721,6 +2708,10 @@
 			}
 		fprintf(fp, "\n");
 	}
+
+	setlocale(LC_ALL, old_locale);
+	free(old_locale);
+
 	if (ferror(fp) != 0 || fclose(fp) != 0) return -1;
 	else return 0;
 }
@@ -2750,7 +2741,10 @@
 {
 	FILE *fp = fopen(model_file_name,"rb");
 	if(fp==NULL) return NULL;
-	
+
+	char *old_locale = strdup(setlocale(LC_ALL, NULL));
+	setlocale(LC_ALL, "C");
+
 	// read parameters
 
 	svm_model *model = Malloc(svm_model,1);
@@ -2781,6 +2775,9 @@
 			if(svm_type_table[i] == NULL)
 			{
 				fprintf(stderr,"unknown svm type.\n");
+				
+				setlocale(LC_ALL, old_locale);
+				free(old_locale);
 				free(model->rho);
 				free(model->label);
 				free(model->nSV);
@@ -2803,6 +2800,9 @@
 			if(kernel_type_table[i] == NULL)
 			{
 				fprintf(stderr,"unknown kernel function.\n");
+				
+				setlocale(LC_ALL, old_locale);
+				free(old_locale);
 				free(model->rho);
 				free(model->label);
 				free(model->nSV);
@@ -2867,6 +2867,9 @@
 		else
 		{
 			fprintf(stderr,"unknown text in model file: [%s]\n",cmd);
+			
+			setlocale(LC_ALL, old_locale);
+			free(old_locale);
 			free(model->rho);
 			free(model->label);
 			free(model->nSV);
@@ -2939,6 +2942,9 @@
 	}
 	free(line);
 
+	setlocale(LC_ALL, old_locale);
+	free(old_locale);
+
 	if (ferror(fp) != 0 || fclose(fp) != 0)
 		return NULL;
 
@@ -2946,20 +2952,46 @@
 	return model;
 }
 
-void svm_destroy_model(svm_model* model)
+void svm_free_model_content(svm_model* model_ptr)
 {
-	if(model->free_sv && model->l > 0)
-		free((void *)(model->SV[0]));
-	for(int i=0;i<model->nr_class-1;i++)
-		free(model->sv_coef[i]);
-	free(model->SV);
-	free(model->sv_coef);
-	free(model->rho);
-	free(model->label);
-	free(model->probA);
-	free(model->probB);
-	free(model->nSV);
-	free(model);
+	if(model_ptr->free_sv && model_ptr->l > 0 && model_ptr->SV != NULL)
+		free((void *)(model_ptr->SV[0]));
+	if(model_ptr->sv_coef)
+	{
+		for(int i=0;i<model_ptr->nr_class-1;i++)
+			free(model_ptr->sv_coef[i]);
+	}
+
+	free(model_ptr->SV);
+	model_ptr->SV = NULL;
+
+	free(model_ptr->sv_coef);
+	model_ptr->sv_coef = NULL;
+
+	free(model_ptr->rho);
+	model_ptr->rho = NULL;
+
+	free(model_ptr->label);
+	model_ptr->label= NULL;
+
+	free(model_ptr->probA);
+	model_ptr->probA = NULL;
+
+	free(model_ptr->probB);
+	model_ptr->probB= NULL;
+
+	free(model_ptr->nSV);
+	model_ptr->nSV = NULL;
+}
+
+void svm_free_and_destroy_model(svm_model** model_ptr_ptr)
+{
+	if(model_ptr_ptr != NULL && *model_ptr_ptr != NULL)
+	{
+		svm_free_model_content(*model_ptr_ptr);
+		free(*model_ptr_ptr);
+		*model_ptr_ptr = NULL;
+	}
 }
 
 void svm_destroy_param(svm_parameter* param)
@@ -3096,3 +3128,11 @@
 		((model->param.svm_type == EPSILON_SVR || model->param.svm_type == NU_SVR) &&
 		 model->probA!=NULL);
 }
+
+void svm_set_print_string_function(void (*print_func)(const char *))
+{
+	if(print_func == NULL)
+		svm_print_string = &print_string_stdout;
+	else
+		svm_print_string = print_func;
+}
--- a/extra/NaN/src/svm.h	Thu Apr 09 17:43:15 2015 +0000
+++ b/extra/NaN/src/svm.h	Sun Apr 12 14:37:46 2015 +0000
@@ -1,10 +1,12 @@
 /*
-This code was extracted from libsvm-mat-2.9-1 in Jan 2010 
-Copyright (C) 2010 Alois Schloegl <alois.schloegl@gmail.com>
+
+This code was extracted from libsvm-3.12 in Apr 2015 and 
+modified for the use with Octave 
+Copyright (c) 2010,2011,2015 Alois Schloegl <alois.schloegl@ist.ac.at>
 This function is part of the NaN-toolbox
 http://pub.ist.ac.at/~schloegl/matlab/NaN/
 
-Copyright (c) 2000-2009 Chih-Chung Chang and Chih-Jen Lin
+Copyright (c) 2000-2012 Chih-Chung Chang and Chih-Jen Lin
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -42,7 +44,7 @@
 #ifndef _LIBSVM_H
 #define _LIBSVM_H
 
-#define LIBSVM_VERSION 290 
+#define LIBSVM_VERSION 312
 
 #ifdef __cplusplus
 extern "C" {
@@ -87,6 +89,9 @@
 	int probability; /* do probability estimates */
 };
 
+//
+// svm_model
+// 
 struct svm_model
 {
 	struct svm_parameter param;	/* parameter */
@@ -119,17 +124,18 @@
 void svm_get_labels(const struct svm_model *model, int *label);
 double svm_get_svr_probability(const struct svm_model *model);
 
-void svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values);
+double svm_predict_values(const struct svm_model *model, const struct svm_node *x, double* dec_values);
 double svm_predict(const struct svm_model *model, const struct svm_node *x);
 double svm_predict_probability(const struct svm_model *model, const struct svm_node *x, double* prob_estimates);
 
-void svm_destroy_model(struct svm_model *model);
+void svm_free_model_content(struct svm_model *model_ptr);
+void svm_free_and_destroy_model(struct svm_model **model_ptr_ptr);
 void svm_destroy_param(struct svm_parameter *param);
 
 const char *svm_check_parameter(const struct svm_problem *prob, const struct svm_parameter *param);
 int svm_check_probability_model(const struct svm_model *model);
 
-extern void (*svm_print_string) (const char *);
+void svm_set_print_string_function(void (*print_func)(const char *));
 
 #ifdef __cplusplus
 }
--- a/extra/NaN/src/svm_model_matlab.c	Thu Apr 09 17:43:15 2015 +0000
+++ b/extra/NaN/src/svm_model_matlab.c	Sun Apr 12 14:37:46 2015 +0000
@@ -372,7 +372,7 @@
 		pprhs[0] = rhs[id];
 		if(mexCallMATLAB(1, pplhs, 1, pprhs, "transpose")) 
 		{
-			svm_destroy_model(model);
+			svm_free_and_destroy_model(model);
 			*msg = "cannot transpose SV matrix";
 			return NULL;
 		}
--- a/extra/NaN/src/svmpredict_mex.cpp	Thu Apr 09 17:43:15 2015 +0000
+++ b/extra/NaN/src/svmpredict_mex.cpp	Sun Apr 12 14:37:46 2015 +0000
@@ -1,12 +1,12 @@
 /*
 
 $Id$
-Copyright (c) 2000-2009 Chih-Chung Chang and Chih-Jen Lin
-Copyright (c) 2010,2011 Alois Schloegl <alois.schloegl@gmail.com>
+Copyright (c) 2000-2012 Chih-Chung Chang and Chih-Jen Lin
+Copyright (c) 2010,2011,2015 Alois Schloegl <alois.schloegl@ist.ac.at>
 This function is part of the NaN-toolbox
 http://pub.ist.ac.at/~schloegl/matlab/NaN/
 
-This code was extracted from libsvm-mat-2.9-1 in Jan 2010 and 
+This code was extracted from libsvm-3.12 in Apr 2015 and 
 modified for the use with Octave 
 
 This program is free software; you can redistribute it and/or modify
@@ -164,7 +164,8 @@
 		// decision values are in plhs[2]
 		if(svm_type == ONE_CLASS ||
 		   svm_type == EPSILON_SVR ||
-		   svm_type == NU_SVR)
+		   svm_type == NU_SVR ||
+		   nr_class == 1) // if only one class in training data, decision values are still returned.
 			plhs[2] = mxCreateDoubleMatrix(testing_instance_number, 1, mxREAL);
 		else
 			plhs[2] = mxCreateDoubleMatrix(testing_instance_number, nr_class*(nr_class-1)/2, mxREAL);
@@ -208,25 +209,26 @@
 		}
 		else
 		{
-			predict_label = svm_predict(model,x);
-			ptr_predict_label[instance_index] = predict_label;
-
 			if(svm_type == ONE_CLASS ||
 			   svm_type == EPSILON_SVR ||
 			   svm_type == NU_SVR)
 			{
 				double res;
-				svm_predict_values(model, x, &res);
+				predict_label = svm_predict_values(model, x, &res);
 				ptr_dec_values[instance_index] = res;
 			}
 			else
 			{
 				double *dec_values = (double *) malloc(sizeof(double) * nr_class*(nr_class-1)/2);
-				svm_predict_values(model, x, dec_values);
-				for(i=0;i<(nr_class*(nr_class-1))/2;i++)
-					ptr_dec_values[instance_index + i * testing_instance_number] = dec_values[i];
+				predict_label = svm_predict_values(model, x, dec_values);
+				if(nr_class == 1) 
+					ptr_dec_values[instance_index] = 1;
+				else
+					for(i=0;i<(nr_class*(nr_class-1))/2;i++)
+						ptr_dec_values[instance_index + i * testing_instance_number] = dec_values[i];
 				free(dec_values);
 			}
+			ptr_predict_label[instance_index] = predict_label;
 		}
 
 		if(predict_label == target_label)
@@ -239,9 +241,7 @@
 		sumpt += predict_label*target_label;
 		++total;
 	}
-	if (1)
-		;	// avoid output to command line
-	else if(svm_type==NU_SVR || svm_type==EPSILON_SVR)
+	if(svm_type==NU_SVR || svm_type==EPSILON_SVR)
 	{
 		mexPrintf("Mean squared error = %g (regression)\n",error/total);
 		mexPrintf("Squared correlation coefficient = %g (regression)\n",
@@ -269,7 +269,7 @@
 void exit_with_help()
 {
 	mexPrintf(
-		"Usage: [predicted_label, accuracy, decision_values/prob_estimates] = svmpredict(testing_label_vector, testing_instance_matrix, model, 'libsvm_options')\n"
+		"Usage: [predicted_label, accuracy, decision_values/prob_estimates] = svmpredict_mex(testing_label_vector, testing_instance_matrix, model, 'libsvm_options')\n"
 		"Parameters:\n"
 		"  model: SVM model structure from svmtrain.\n"
 		"  libsvm_options:\n"
@@ -353,19 +353,19 @@
 			{
 				mexPrintf("Model does not support probabiliy estimates\n");
 				fake_answer(plhs);
-				svm_destroy_model(model);
+				svm_free_and_destroy_model(&model);
 				return;
 			}
 		}
 		else
 		{
 			if(svm_check_probability_model(model)!=0)
-				printf("Model supports probability estimates, but disabled in predicton.\n");
+				mexPrintf("Model supports probability estimates, but disabled in predicton.\n");
 		}
 
 		predict(plhs, prhs, model, prob_estimate_flag);
 		// destroy model
-		svm_destroy_model(model);
+		svm_free_and_destroy_model(&model);
 	}
 	else
 	{
--- a/extra/NaN/src/svmtrain_mex.cpp	Thu Apr 09 17:43:15 2015 +0000
+++ b/extra/NaN/src/svmtrain_mex.cpp	Sun Apr 12 14:37:46 2015 +0000
@@ -1,12 +1,12 @@
 /*
 
 $Id$
-Copyright (c) 2000-2009 Chih-Chung Chang and Chih-Jen Lin
-Copyright (c) 2010 Alois Schloegl <alois.schloegl@gmail.com>
+Copyright (c) 2000-2012 Chih-Chung Chang and Chih-Jen Lin
+Copyright (c) 2010,2015 Alois Schloegl <alois.schloegl@ist.ac.at>
 This function is part of the NaN-toolbox
 http://pub.ist.ac.at/~schloegl/matlab/NaN/
 
-This code was extracted from libsvm-mat-2.9-1 in Jan 2010 and 
+This code was extracted from libsvm-3.12 in Apr 2015 and 
 modified for the use with Octave 
 
 This program is free software; you can redistribute it and/or modify
@@ -45,6 +45,7 @@
 #define Malloc(type,n) (type *)malloc((n)*sizeof(type))
 
 void print_null(const char *s) {}
+void print_string_matlab(const char *s) {mexPrintf(s);}
 
 void exit_with_help()
 {
@@ -87,7 +88,6 @@
 int cross_validation;
 int nr_fold;
 
-void (*svm_default_print_string) (const char *) = NULL;
 
 double do_cross_validation()
 {
@@ -138,6 +138,7 @@
 	int i, argc = 1;
 	char cmd[CMD_LEN];
 	char *argv[CMD_LEN/2];
+	void (*print_func)(const char *) = print_string_matlab;	// default printing to matlab display
 
 	// default values
 	param.svm_type = C_SVC;
@@ -156,12 +157,6 @@
 	param.weight_label = NULL;
 	param.weight = NULL;
 	cross_validation = 0;
-	// svmtrain loaded only once under matlab
-	if (svm_default_print_string == NULL)
-		svm_default_print_string = svm_print_string;
-	else
-		svm_print_string = svm_default_print_string;
-
 
 	if(nrhs <= 1)
 		return 1;
@@ -221,7 +216,7 @@
 				param.probability = atoi(argv[i]);
 				break;
 			case 'q':
-				svm_print_string = &print_null;
+				print_func = &print_null;
 				i--;
 				break;
 			case 'v':
@@ -245,6 +240,9 @@
 				return 1;
 		}
 	}
+
+	svm_set_print_string_function(print_func);
+
 	return 0;
 }
 
@@ -415,7 +413,7 @@
 	srand(1);
 
 	// Transform the input Matrix to libsvm format
-	if(nrhs > 0 && nrhs < 4)
+	if(nrhs > 1 && nrhs < 4)
 	{
 		int err;
 
@@ -488,7 +486,7 @@
 			error_msg = model_to_matlab_structure(plhs, nr_feat, model);
 			if(error_msg)
 				mexPrintf("Error: can't convert libsvm model to matrix structure: %s\n", error_msg);
-			svm_destroy_model(model);
+			svm_free_and_destroy_model(&model);
 		}
 		svm_destroy_param(&param);
 		free(prob.y);