const-fixing functions
[mldemos:mldemos.git] / _AlgorithmsPlugins / KernelMethods / classifierMVM.cpp
1 /*********************************************************************\r
2 MLDemos: A User-Friendly visualization toolkit for machine learning\r
3 Copyright (C) 2010  Basilio Noris\r
4 Contact: mldemos@b4silio.com\r
5 \r
6 This library is free software; you can redistribute it and/or\r
7 modify it under the terms of the GNU Lesser General Public\r
8 License as published by the Free Software Foundation; either\r
9 version 2.1 of the License, or (at your option) any later version.\r
10 \r
11 This library is distributed in the hope that it will be useful,\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
14 Library General Public License for more details.\r
15 \r
16 You should have received a copy of the GNU Lesser General Public\r
17 License along with this library; if not, write to the Free\r
18 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\r
19 *********************************************************************/\r
20 #include <public.h>\r
21 #include "classifierMVM.h"\r
22 #include <QDebug>\r
23 \r
24 using namespace std;\r
25 \r
26 ClassifierMVM::ClassifierMVM()\r
27 {\r
28     SVs = 0;\r
29     alpha = 0;\r
30     svCount = 0;\r
31     b = 0;\r
32 \r
33     kernel_type = 0;\r
34     degree = 1;\r
35     gamma = 0.1;\r
36     coef0 = 0.;\r
37 }\r
38 \r
39 ClassifierMVM::~ClassifierMVM()\r
40 {\r
41     if(SVs)\r
42     {\r
43         FOR(i, svCount)\r
44         {\r
45             KILL(SVs[i]);\r
46         }\r
47         KILL(SVs);\r
48     }\r
49     KILL(alpha);\r
50 }\r
51 \r
52 void ClassifierMVM::SetParams(u32 kernelType, float kernelParam, ivec indices, fvec alphas)\r
53 {\r
54     this->indices = indices;\r
55     this->alphas = alphas;\r
56 \r
57     // default values\r
58     coef0 = 0;\r
59     gamma = 1;\r
60 \r
61     switch(kernelType)\r
62     {\r
63     case 0:\r
64         kernel_type = LINEAR;\r
65         degree = 1;\r
66         break;\r
67     case 1:\r
68         kernel_type = POLY;\r
69         degree = (u32)kernelParam;\r
70         break;\r
71     case 2:\r
72         kernel_type = RBF;\r
73         gamma = kernelParam;\r
74         break;\r
75     case 3:\r
76         kernel_type = SIGMOID;\r
77         gamma = kernelParam;\r
78         break;\r
79     }\r
80 }\r
81 \r
82 float Kernel(const float* x, const float *sv, const int dim, const int kernelType, const int degree, const float gamma, const float coef0)\r
83 {\r
84     float sum = 0.f;\r
85     switch(kernelType)\r
86     {\r
87     case 0: // LINEAR\r
88     {\r
89         FOR(d, dim) sum += x[d]*sv[d];\r
90     }\r
91         break;\r
92     case 1: // POLY\r
93     {\r
94         FOR(d, dim) sum += x[d]*sv[d];\r
95         sum += coef0;\r
96         sum = powf(sum, degree);\r
97     }\r
98         break;\r
99     case 2: // RBF\r
100     {\r
101         FOR(d, dim)\r
102         {\r
103             float diff = x[d]-sv[d];\r
104             sum += (diff)*(diff)*gamma;\r
105         }\r
106         sum = expf(-sum);\r
107     }\r
108         break;\r
109     case 3: // SIGMOID\r
110         break;\r
111     }\r
112 \r
113     return sum;\r
114 }\r
115 \r
116 void ClassifierMVM::Train(std::vector< fvec > _samples, ivec _labels)\r
117 {\r
118     if(!manualSamples.size()) return;\r
119     svCount = indices.size();\r
120     if(SVs)\r
121     {\r
122         FOR(i, svCount)\r
123         {\r
124             KILL(SVs[i]);\r
125         }\r
126         KILL(SVs);\r
127         KILL(alpha);\r
128     }\r
129     if(!indices.size()) return;\r
130 \r
131     dim = manualSamples[0].size();\r
132 \r
133     SVs = new float*[indices.size()];\r
134     alpha = new float[indices.size()];\r
135     FOR(i, indices.size())\r
136     {\r
137         SVs[i] = new float[dim];\r
138         FOR(d, dim)\r
139         {\r
140             SVs[i][d] = manualSamples[indices[i]][d];\r
141         }\r
142         alpha[i] = alphas[i];\r
143     }\r
144 \r
145     // we compute the b;\r
146     b = 0;\r
147     float sum = 0;\r
148     FOR(i, svCount)\r
149     {\r
150         float y = 0;\r
151         FOR(j, svCount)\r
152         {\r
153             y += alpha[j]*Kernel(SVs[i], SVs[j], dim, kernel_type, degree, gamma, coef0);\r
154         }\r
155         sum += (y - manualLabels[i]);\r
156     }\r
157     b = sum / svCount;\r
158 }\r
159 \r
160 float ClassifierMVM::Test( const fvec &sample ) const\r
161 {\r
162     if(!SVs || !svCount) return 0.f;\r
163 \r
164     float estimate = 0;\r
165 \r
166     // we compute the kernel\r
167     FOR(i, svCount)\r
168     {\r
169         estimate += alpha[i]*Kernel(&sample[0], SVs[i], dim, kernel_type, degree, gamma, coef0);\r
170     }\r
171 \r
172     return estimate - b;\r
173 }\r
174 \r
175 const char *ClassifierMVM::GetInfoString() const\r
176 {\r
177     char *text = new char[1024];\r
178     sprintf(text, "MVM\n");\r
179     sprintf(text, "%sKernel: ", text);\r
180     switch(kernel_type)\r
181     {\r
182     case LINEAR:\r
183         sprintf(text, "%s linear\n", text);\r
184         break;\r
185     case POLY:\r
186         sprintf(text, "%s polynomial (deg: %d bias: %.3f width: %f)\n", text, degree, coef0, gamma);\r
187         break;\r
188     case RBF:\r
189         sprintf(text, "%s rbf (gamma: %f)\n", text, gamma);\r
190         break;\r
191     case SIGMOID:\r
192         sprintf(text, "%s sigmoid (%f %f)\n", text, gamma, coef0);\r
193         break;\r
194     }\r
195     sprintf(text, "%sSupport Vectors: %d\n", text, svCount);\r
196     return text;\r
197 }\r