diff --git a/svm.cpp b/svm.cpp index 01e1b5ed..0af268f7 100644 --- a/svm.cpp +++ b/svm.cpp @@ -188,6 +188,37 @@ void Cache::swap_index(int i, int j) } } +// Provides access to the elements in a single column of a QMatrix. +class QColumn { +public: + QColumn(const Qfloat *values, int column_idx, double diagonal_value) + : values(values), column_idx(column_idx), diagonal_value(diagonal_value) { + } + + double operator[](int row_idx) const { + if (row_idx != column_idx) { + return values[row_idx]; + } else { + // Return the value from the QD array so that calculations stay + // consistent, regardless of whether QColumn or the QD array + // are used. + // + // QD array is double precision while Qfloat could be single + // precision, so the diagonal values could be very different + // between the two. If one calculation uses QColumn while + // another calculation uses the QD array, the optimization + // algorithm may not converge. + return diagonal_value; + } + } + +private: + const Qfloat *values; + + int column_idx; + double diagonal_value; +}; + // // Kernel evaluation // @@ -197,7 +228,7 @@ void Cache::swap_index(int i, int j) // class QMatrix { public: - virtual Qfloat *get_Q(int column, int len) const = 0; + virtual QColumn get_Q(int column, int len) const = 0; virtual double *get_QD() const = 0; virtual void swap_index(int i, int j) const = 0; virtual ~QMatrix() {} @@ -210,7 +241,7 @@ class Kernel: public QMatrix { 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 QColumn get_Q(int column, int len) const = 0; virtual double *get_QD() const = 0; virtual void swap_index(int i, int j) const // no so const... { @@ -486,7 +517,7 @@ void Solver::reconstruct_gradient() { for(i=active_size;iget_Q(i,active_size); + QColumn Q_i = Q->get_Q(i,active_size); for(j=0;jget_Q(i,l); + QColumn Q_i = Q->get_Q(i,l); double alpha_i = alpha[i]; for(j=active_size;jget_Q(i,active_size); + if (i == -1) { + return 1; + } + + QColumn Q_i = Q->get_Q(i,active_size); for(int j=0;jget_Q(ip,active_size); if(in != -1) @@ -1280,7 +1313,7 @@ class SVC_Q: public Kernel QD[i] = (this->*kernel_function)(i,i); } - Qfloat *get_Q(int i, int len) const + QColumn get_Q(int i, int len) const { Qfloat *data; int start, j; @@ -1292,7 +1325,7 @@ class SVC_Q: public Kernel for(j=start;j*kernel_function)(i,j)); } - return data; + return QColumn(data, i, QD[i]); } double *get_QD() const @@ -1332,7 +1365,7 @@ class ONE_CLASS_Q: public Kernel QD[i] = (this->*kernel_function)(i,i); } - Qfloat *get_Q(int i, int len) const + QColumn get_Q(int i, int len) const { Qfloat *data; int start, j; @@ -1341,7 +1374,7 @@ class ONE_CLASS_Q: public Kernel for(j=start;j*kernel_function)(i,j); } - return data; + return QColumn(data, i, QD[i]); } double *get_QD() const @@ -1398,7 +1431,7 @@ class SVR_Q: public Kernel swap(QD[i],QD[j]); } - Qfloat *get_Q(int i, int len) const + QColumn get_Q(int i, int len) const { Qfloat *data; int j, real_i = index[i]; @@ -1417,7 +1450,7 @@ class SVR_Q: public Kernel schar si = sign[i]; for(j=0;j