[2645] | 1 | using System;
|
---|
| 2 |
|
---|
[4068] | 3 | namespace SVM {
|
---|
| 4 | internal interface IQMatrix {
|
---|
| 5 | float[] GetQ(int column, int len);
|
---|
| 6 | float[] GetQD();
|
---|
| 7 | void SwapIndex(int i, int j);
|
---|
| 8 | }
|
---|
[2645] | 9 |
|
---|
[4068] | 10 | internal abstract class Kernel : IQMatrix {
|
---|
| 11 | private Node[][] _x;
|
---|
| 12 | private double[] _xSquare;
|
---|
[2645] | 13 |
|
---|
[4068] | 14 | private KernelType _kernelType;
|
---|
| 15 | private int _degree;
|
---|
| 16 | private double _gamma;
|
---|
| 17 | private double _coef0;
|
---|
[2645] | 18 |
|
---|
[4068] | 19 | public abstract float[] GetQ(int column, int len);
|
---|
| 20 | public abstract float[] GetQD();
|
---|
[2645] | 21 |
|
---|
[4068] | 22 | public virtual void SwapIndex(int i, int j) {
|
---|
| 23 | _x.SwapIndex(i, j);
|
---|
[2645] | 24 |
|
---|
[4068] | 25 | if (_xSquare != null) {
|
---|
| 26 | _xSquare.SwapIndex(i, j);
|
---|
| 27 | }
|
---|
| 28 | }
|
---|
[2645] | 29 |
|
---|
[4068] | 30 | private static double powi(double value, int times) {
|
---|
| 31 | double tmp = value, ret = 1.0;
|
---|
[2645] | 32 |
|
---|
[4068] | 33 | for (int t = times; t > 0; t /= 2) {
|
---|
| 34 | if (t % 2 == 1) ret *= tmp;
|
---|
| 35 | tmp = tmp * tmp;
|
---|
| 36 | }
|
---|
| 37 | return ret;
|
---|
| 38 | }
|
---|
[2645] | 39 |
|
---|
[4068] | 40 | public double KernelFunction(int i, int j) {
|
---|
| 41 | switch (_kernelType) {
|
---|
| 42 | case KernelType.LINEAR:
|
---|
| 43 | return dot(_x[i], _x[j]);
|
---|
| 44 | case KernelType.POLY:
|
---|
| 45 | return powi(_gamma * dot(_x[i], _x[j]) + _coef0, _degree);
|
---|
| 46 | case KernelType.RBF:
|
---|
| 47 | return Math.Exp(-_gamma * (_xSquare[i] + _xSquare[j] - 2 * dot(_x[i], _x[j])));
|
---|
| 48 | case KernelType.SIGMOID:
|
---|
| 49 | return Math.Tanh(_gamma * dot(_x[i], _x[j]) + _coef0);
|
---|
| 50 | case KernelType.PRECOMPUTED:
|
---|
| 51 | return _x[i][(int)(_x[j][0].Value)].Value;
|
---|
| 52 | default:
|
---|
| 53 | return 0;
|
---|
| 54 | }
|
---|
| 55 | }
|
---|
[2645] | 56 |
|
---|
[4068] | 57 | public Kernel(int l, Node[][] x_, Parameter param) {
|
---|
| 58 | _kernelType = param.KernelType;
|
---|
| 59 | _degree = param.Degree;
|
---|
| 60 | _gamma = param.Gamma;
|
---|
| 61 | _coef0 = param.Coefficient0;
|
---|
[2645] | 62 |
|
---|
[4068] | 63 | _x = (Node[][])x_.Clone();
|
---|
[2645] | 64 |
|
---|
[4068] | 65 | if (_kernelType == KernelType.RBF) {
|
---|
| 66 | _xSquare = new double[l];
|
---|
| 67 | for (int i = 0; i < l; i++)
|
---|
| 68 | _xSquare[i] = dot(_x[i], _x[i]);
|
---|
| 69 | } else _xSquare = null;
|
---|
| 70 | }
|
---|
[2645] | 71 |
|
---|
[4068] | 72 | private static double dot(Node[] xNodes, Node[] yNodes) {
|
---|
| 73 | double sum = 0;
|
---|
| 74 | int xlen = xNodes.Length;
|
---|
| 75 | int ylen = yNodes.Length;
|
---|
| 76 | int i = 0;
|
---|
| 77 | int j = 0;
|
---|
| 78 | Node x = xNodes[0];
|
---|
| 79 | Node y = yNodes[0];
|
---|
| 80 | while (true) {
|
---|
| 81 | if (x._index == y._index) {
|
---|
| 82 | sum += x._value * y._value;
|
---|
| 83 | i++;
|
---|
| 84 | j++;
|
---|
| 85 | if (i < xlen && j < ylen) {
|
---|
| 86 | x = xNodes[i];
|
---|
| 87 | y = yNodes[j];
|
---|
| 88 | } else if (i < xlen) {
|
---|
| 89 | x = xNodes[i];
|
---|
| 90 | break;
|
---|
| 91 | } else if (j < ylen) {
|
---|
| 92 | y = yNodes[j];
|
---|
| 93 | break;
|
---|
| 94 | } else break;
|
---|
| 95 | } else {
|
---|
| 96 | if (x._index > y._index) {
|
---|
| 97 | ++j;
|
---|
| 98 | if (j < ylen)
|
---|
| 99 | y = yNodes[j];
|
---|
| 100 | else break;
|
---|
| 101 | } else {
|
---|
| 102 | ++i;
|
---|
| 103 | if (i < xlen)
|
---|
| 104 | x = xNodes[i];
|
---|
| 105 | else break;
|
---|
| 106 | }
|
---|
[2645] | 107 | }
|
---|
[4068] | 108 | }
|
---|
| 109 | return sum;
|
---|
| 110 | }
|
---|
[2645] | 111 |
|
---|
[4068] | 112 | private static double computeSquaredDistance(Node[] xNodes, Node[] yNodes) {
|
---|
| 113 | Node x = xNodes[0];
|
---|
| 114 | Node y = yNodes[0];
|
---|
| 115 | int xLength = xNodes.Length;
|
---|
| 116 | int yLength = yNodes.Length;
|
---|
| 117 | int xIndex = 0;
|
---|
| 118 | int yIndex = 0;
|
---|
| 119 | double sum = 0;
|
---|
[2645] | 120 |
|
---|
[4068] | 121 | while (true) {
|
---|
| 122 | if (x._index == y._index) {
|
---|
| 123 | double d = x._value - y._value;
|
---|
| 124 | sum += d * d;
|
---|
| 125 | xIndex++;
|
---|
| 126 | yIndex++;
|
---|
| 127 | if (xIndex < xLength && yIndex < yLength) {
|
---|
| 128 | x = xNodes[xIndex];
|
---|
| 129 | y = yNodes[yIndex];
|
---|
| 130 | } else if (xIndex < xLength) {
|
---|
| 131 | x = xNodes[xIndex];
|
---|
| 132 | break;
|
---|
| 133 | } else if (yIndex < yLength) {
|
---|
| 134 | y = yNodes[yIndex];
|
---|
| 135 | break;
|
---|
| 136 | } else break;
|
---|
| 137 | } else if (x._index > y._index) {
|
---|
| 138 | sum += y._value * y._value;
|
---|
| 139 | if (++yIndex < yLength)
|
---|
| 140 | y = yNodes[yIndex];
|
---|
| 141 | else break;
|
---|
| 142 | } else {
|
---|
| 143 | sum += x._value * x._value;
|
---|
| 144 | if (++xIndex < xLength)
|
---|
| 145 | x = xNodes[xIndex];
|
---|
| 146 | else break;
|
---|
| 147 | }
|
---|
| 148 | }
|
---|
[2645] | 149 |
|
---|
[4068] | 150 | for (; xIndex < xLength; xIndex++) {
|
---|
| 151 | double d = xNodes[xIndex]._value;
|
---|
| 152 | sum += d * d;
|
---|
| 153 | }
|
---|
[2645] | 154 |
|
---|
[4068] | 155 | for (; yIndex < yLength; yIndex++) {
|
---|
| 156 | double d = yNodes[yIndex]._value;
|
---|
| 157 | sum += d * d;
|
---|
| 158 | }
|
---|
[2645] | 159 |
|
---|
[4068] | 160 | return sum;
|
---|
| 161 | }
|
---|
[2645] | 162 |
|
---|
[4068] | 163 | public static double KernelFunction(Node[] x, Node[] y, Parameter param) {
|
---|
| 164 | switch (param.KernelType) {
|
---|
| 165 | case KernelType.LINEAR:
|
---|
| 166 | return dot(x, y);
|
---|
| 167 | case KernelType.POLY:
|
---|
| 168 | return powi(param.Degree * dot(x, y) + param.Coefficient0, param.Degree);
|
---|
| 169 | case KernelType.RBF: {
|
---|
| 170 | double sum = computeSquaredDistance(x, y);
|
---|
| 171 | return Math.Exp(-param.Gamma * sum);
|
---|
| 172 | }
|
---|
| 173 | case KernelType.SIGMOID:
|
---|
| 174 | return Math.Tanh(param.Gamma * dot(x, y) + param.Coefficient0);
|
---|
| 175 | case KernelType.PRECOMPUTED:
|
---|
| 176 | return x[(int)(y[0].Value)].Value;
|
---|
| 177 | default:
|
---|
| 178 | return 0;
|
---|
| 179 | }
|
---|
[2645] | 180 | }
|
---|
[4068] | 181 | }
|
---|
[2645] | 182 | }
|
---|