/**
* Copyright (c) 2000-2005 Chih-Chung Chang and Chih-Jen Lin All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. Neither name of copyright holders nor the names of its contributors may be used to endorse or
* promote products derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
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;
@Override
abstract float[] get_Q(int column, int len);
@Override
abstract float[] get_QD();
@Override
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
}
}
}