/* * RapidMiner * * Copyright (C) 2001-2008 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package libsvm; public abstract class Kernel extends QMatrix { private svm_node[][] x; private final double[] x_square; // svm_parameter private final int kernel_type; private final int degree; private final double gamma; private final double coef0; abstract float[] get_Q(int column, int len); abstract float[] get_QD(); void swap_index(int i, int j) { do {svm_node[] _=x[i]; x[i]=x[j]; x[j]=_;} while(false); if(x_square != null) do {double _=x_square[i]; x_square[i]=x_square[j]; x_square[j]=_;} while(false); } private static double powi(double base, int times) { double tmp = base, ret = 1.0; for(int t=times; t>0; t/=2) { if(t%2!=0) ret*=tmp; tmp = tmp * tmp; } return ret; } private static double tanh(double x) { double e = Math.exp(x); return 1.0-2.0/(e*e+1); } public double kernel_function(int i, int j) { switch(kernel_type) { case svm_parameter.LINEAR: return dot(x[i],x[j]); case svm_parameter.POLY: return powi(gamma*dot(x[i],x[j])+coef0,degree); case svm_parameter.RBF: return Math.exp(-gamma*(x_square[i]+x_square[j]-2*dot(x[i],x[j]))); case svm_parameter.SIGMOID: return tanh(gamma*dot(x[i],x[j])+coef0); case svm_parameter.PRECOMPUTED: return x[i][(int)(x[j][0].value)].value; default: return 0; // java } } Kernel(int l, svm_node[][] x_, svm_parameter param) { this.kernel_type = param.kernel_type; this.degree = param.degree; this.gamma = param.gamma; this.coef0 = param.coef0; x = x_.clone(); if(kernel_type == svm_parameter.RBF) { x_square = new double[l]; for(int i=0;i<l;i++) x_square[i] = dot(x[i],x[i]); } else x_square = null; } static double dot(svm_node[] x, svm_node[] y) { double sum = 0; int xlen = x.length; int ylen = y.length; int i = 0; int j = 0; while(i < xlen && j < ylen) { if(x[i].index == y[j].index) sum += x[i++].value * y[j++].value; else { if(x[i].index > y[j].index) ++j; else ++i; } } return sum; } static double k_function(svm_node[] x, svm_node[] y, svm_parameter param) { switch(param.kernel_type) { case svm_parameter.LINEAR: return dot(x,y); case svm_parameter.POLY: return powi(param.gamma*dot(x,y)+param.coef0,param.degree); case svm_parameter.RBF: { double sum = 0; int xlen = x.length; int ylen = y.length; int i = 0; int j = 0; while(i < xlen && j < ylen) { if(x[i].index == y[j].index) { double d = x[i++].value - y[j++].value; sum += d*d; } else if(x[i].index > y[j].index) { sum += y[j].value * y[j].value; ++j; } else { sum += x[i].value * x[i].value; ++i; } } while(i < xlen) { sum += x[i].value * x[i].value; ++i; } while(j < ylen) { sum += y[j].value * y[j].value; ++j; } return Math.exp(-param.gamma*sum); } case svm_parameter.SIGMOID: return tanh(param.gamma*dot(x,y)+param.coef0); case svm_parameter.PRECOMPUTED: return x[(int)(y[0].value)].value; default: return 0; // java } } }