- added multiple format support for input data (now supports csv, tabs, ; and spaces)
[mldemos:baraks-mldemos.git] / MLDemos / mlprocessing.cpp
1 /*********************************************************************
2 MLDemos: A User-Friendly visualization toolkit for machine learning
3 Copyright (C) 2010  Basilio Noris
4 Contact: mldemos@b4silio.com
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free
18 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *********************************************************************/
20 #include "mldemos.h"
21 #include "basicMath.h"
22 #include "classifier.h"
23 #include "regressor.h"
24 #include "dynamical.h"
25 #include "clusterer.h"
26 #include "maximize.h"
27 #include "roc.h"
28 #include <QDebug>
29 #include <fstream>
30 #include <QPixmap>
31 #include <QBitmap>
32 #include <QSettings>
33 #include <QFileDialog>
34 #include <QProgressDialog>
35
36 using namespace std;
37
38 void MLDemos::Classify()
39 {
40     if(!canvas || !canvas->data->GetCount()) return;
41     drawTimer->Stop();
42         drawTimer->Clear();
43         mutex.lock();
44     DEL(clusterer);
45     DEL(regressor);
46     DEL(dynamical);
47     DEL(classifier);
48         DEL(maximizer);
49     DEL(projector);
50     int tab = optionsClassify->tabWidget->currentIndex();
51     if(tab >= classifiers.size() || !classifiers[tab]) return;
52     classifier = classifiers[tab]->GetClassifier();
53     tabUsedForTraining = tab;
54     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
55     int ratioIndex = optionsClassify->traintestRatioCombo->currentIndex();
56     float trainRatio = ratios[ratioIndex];
57     int positive = optionsClassify->positiveSpin->value();
58
59     bool trained = Train(classifier, positive, trainRatio);
60     if(trained)
61     {
62                 classifiers[tab]->Draw(canvas, classifier);
63                 UpdateInfo();
64                 if(drawTimer && classifier->UsesDrawTimer())
65         {
66             drawTimer->classifier = &this->classifier;
67             drawTimer->start(QThread::NormalPriority);
68         }
69         if(canvas->canvasType) CanvasZoomChanged();
70         // we fill in the canvas sampleColors
71         vector<fvec> samples = canvas->data->GetSamples();
72         canvas->sampleColors.resize(samples.size());
73         FOR(i, samples.size())
74         {
75             canvas->sampleColors[i] = DrawTimer::GetColor(classifier, samples[i]);
76         }
77         if(canvas->canvasType)
78         {
79             canvas->maps.model = QPixmap();
80             CanvasZoomChanged();
81         }
82     }
83     else
84     {
85         mutex.unlock();
86         Clear();
87                 mutex.lock();
88                 UpdateInfo();
89         }
90         mutex.unlock();
91 }
92
93
94 void MLDemos::ClassifyCross()
95 {
96     if(!canvas || !canvas->data->GetCount()) return;
97     drawTimer->Stop();
98     QMutexLocker lock(&mutex);
99     DEL(clusterer);
100     DEL(regressor);
101     DEL(dynamical);
102     DEL(classifier);
103         DEL(maximizer);
104     DEL(projector);
105     int tab = optionsClassify->tabWidget->currentIndex();
106     if(tab >= classifiers.size() || !classifiers[tab]) return;
107     tabUsedForTraining = tab;
108
109     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
110     int ratioIndex = optionsClassify->traintestRatioCombo->currentIndex();
111     float trainRatio = ratios[ratioIndex];
112     int positive = optionsClassify->positiveSpin->value();
113     int foldCount = optionsClassify->foldCountSpin->value();
114
115     vector<fvec> fmeasures;
116     fmeasures.resize(2);
117     bool trained = false;
118     FOR(f,foldCount)
119     {
120         DEL(classifier);
121         classifier = classifiers[tab]->GetClassifier();
122         trained = Train(classifier, positive, trainRatio);
123         if(!trained) break;
124         if(classifier->rocdata.size()>0)
125         {
126             fmeasures[0].push_back(GetBestFMeasure(classifier->rocdata[0]));
127         }
128         if(classifier->rocdata.size()>1)
129         {
130             fmeasures[1].push_back(GetBestFMeasure(classifier->rocdata[1]));
131         }
132     }
133     classifier->crossval = fmeasures;
134     ShowCross();
135     if(trained) classifiers[tab]->Draw(canvas, classifier);
136     UpdateInfo();
137 }
138
139 void MLDemos::Regression()
140 {
141     if(!canvas || !canvas->data->GetCount()) return;
142     drawTimer->Stop();
143         drawTimer->Clear();
144
145     QMutexLocker lock(&mutex);
146     DEL(clusterer);
147     DEL(regressor);
148     DEL(dynamical);
149     DEL(classifier);
150         DEL(maximizer);
151     DEL(projector);
152     int tab = optionsRegress->tabWidget->currentIndex();
153     if(tab >= regressors.size() || !regressors[tab]) return;
154     regressor = regressors[tab]->GetRegressor();
155     tabUsedForTraining = tab;
156
157     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
158     int ratioIndex = optionsRegress->traintestRatioCombo->currentIndex();
159     float trainRatio = ratios[ratioIndex];
160
161     Train(regressor, trainRatio);
162     regressors[tab]->Draw(canvas, regressor);
163     UpdateInfo();
164 }
165
166 void MLDemos::RegressionCross()
167 {
168     if(!canvas || !canvas->data->GetCount()) return;
169     drawTimer->Stop();
170         drawTimer->Clear();
171         QMutexLocker lock(&mutex);
172     DEL(clusterer);
173     DEL(regressor);
174     DEL(dynamical);
175     DEL(classifier);
176         DEL(maximizer);
177     DEL(projector);
178     int tab = optionsRegress->tabWidget->currentIndex();
179     if(tab >= regressors.size() || !regressors[tab]) return;
180     regressor = regressors[tab]->GetRegressor();
181     tabUsedForTraining = tab;
182
183     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
184     int ratioIndex = optionsRegress->traintestRatioCombo->currentIndex();
185     float trainRatio = ratios[ratioIndex];
186     int foldCount = optionsRegress->foldCountSpin->value();
187
188     vector<fvec> errors;
189     errors.resize(2);
190     bool trained = false;
191     FOR(f,foldCount)
192     {
193         DEL(regressor);
194         regressor = regressors[tab]->GetRegressor();
195         Train(regressor, trainRatio);
196         if(regressor->trainErrors.size())
197         {
198             errors[0] = regressor->trainErrors;
199         }
200         if(regressor->testErrors.size())
201         {
202             errors[1] = regressor->testErrors;
203         }
204     }
205     regressor->crossval = errors;
206     ShowCross();
207
208         Train(regressor, trainRatio);
209     regressors[tab]->Draw(canvas, regressor);
210         UpdateInfo();
211 }
212
213 void MLDemos::Dynamize()
214 {
215     if(!canvas || !canvas->data->GetCount() || !canvas->data->GetSequences().size()) return;
216     drawTimer->Stop();
217         drawTimer->Clear();
218     QMutexLocker lock(&mutex);
219     DEL(clusterer);
220     DEL(regressor);
221     DEL(dynamical);
222     DEL(classifier);
223         DEL(maximizer);
224     DEL(projector);
225     int tab = optionsDynamic->tabWidget->currentIndex();
226     if(tab >= dynamicals.size() || !dynamicals[tab]) return;
227     dynamical = dynamicals[tab]->GetDynamical();
228     tabUsedForTraining = tab;
229
230     Train(dynamical);
231     dynamicals[tab]->Draw(canvas,dynamical);
232
233         int w = canvas->width(), h = canvas->height();
234
235         int resampleType = optionsDynamic->resampleCombo->currentIndex();
236         int resampleCount = optionsDynamic->resampleSpin->value();
237         int centerType = optionsDynamic->centerCombo->currentIndex();
238         float dT = optionsDynamic->dtSpin->value();
239         int zeroEnding = optionsDynamic->zeroCheck->isChecked();
240         bool bColorMap = optionsDynamic->colorCheck->isChecked();
241
242         vector< vector<fvec> > trajectories = canvas->data->GetTrajectories(resampleType, resampleCount, centerType, dT, zeroEnding);
243         if(trajectories.size())
244         {
245                 canvas->maps.model = QPixmap(w,h);
246                 QBitmap bitmap(w,h);
247                 bitmap.clear();
248                 canvas->maps.model.setMask(bitmap);
249                 canvas->maps.model.fill(Qt::transparent);
250                 QPainter painter(&canvas->maps.model);
251                 int dim = trajectories[0][0].size() / 2;
252                 fvec start(dim,0);
253                 FOR(i, trajectories.size())
254                 {
255                         FOR(d, dim) start[d] = trajectories[i][0][d];
256                         vector<fvec> result = dynamical->Test(start, 1000);
257                         fvec oldPt = result[0];
258                         int count = result.size();
259                         FOR(j, count-1)
260                         {
261                                 fvec pt = result[j+1];
262                                 painter.setPen(QPen(Qt::green, 2));
263                                 painter.drawLine(canvas->toCanvasCoords(pt), canvas->toCanvasCoords(oldPt));
264                                 //if(j<count-2) Canvas::drawSample(painter, canvas->toCanvasCoords(pt), 5, 2);
265                                 oldPt = pt;
266                         }
267                         painter.setBrush(Qt::NoBrush);
268                         painter.setPen(Qt::green);
269                         painter.drawEllipse(canvas->toCanvasCoords(result[0]), 5, 5);
270                         painter.setPen(Qt::red);
271                         painter.drawEllipse(canvas->toCanvasCoords(result[count-1]), 5, 5);
272                 }
273         }
274
275         // the first index is "none", so we subtract 1
276     int avoidIndex = optionsDynamic->obstacleCombo->currentIndex()-1;
277     if(avoidIndex >=0 && avoidIndex < avoiders.size() && avoiders[avoidIndex])
278     {
279         DEL(dynamical->avoid);
280                 dynamical->avoid = avoiders[avoidIndex]->GetObstacleAvoidance();
281     }
282         UpdateInfo();
283         if(dynamicals[tab]->UsesDrawTimer())
284         {
285                 drawTimer->bColorMap = bColorMap;
286                 drawTimer->start(QThread::NormalPriority);
287         }
288 }
289
290 void MLDemos::Avoidance()
291 {
292     if(!canvas || !dynamical) return;
293     drawTimer->Stop();
294     QMutexLocker lock(&mutex);
295         // the first index is "none", so we subtract 1
296         int index = optionsDynamic->obstacleCombo->currentIndex()-1;
297     if(index >=0 && index >= avoiders.size() || !avoiders[index]) return;
298     DEL(dynamical->avoid);
299     dynamical->avoid = avoiders[index]->GetObstacleAvoidance();
300         UpdateInfo();
301         drawTimer->Clear();
302     drawTimer->start(QThread::NormalPriority);
303 }
304
305 void MLDemos::Cluster()
306 {
307     if(!canvas || !canvas->data->GetCount()) return;
308     drawTimer->Stop();
309     QMutexLocker lock(&mutex);
310     DEL(clusterer);
311     DEL(regressor);
312     DEL(dynamical);
313     DEL(classifier);
314         DEL(maximizer);
315     DEL(projector);
316     int tab = optionsCluster->tabWidget->currentIndex();
317     if(tab >= clusterers.size() || !clusterers[tab]) return;
318     clusterer = clusterers[tab]->GetClusterer();
319     tabUsedForTraining = tab;
320     Train(clusterer);
321         drawTimer->Stop();
322         drawTimer->Clear();
323     clusterers[tab]->Draw(canvas,clusterer);
324
325     // we fill in the canvas sampleColors
326     vector<fvec> samples = canvas->data->GetSamples();
327     canvas->sampleColors.resize(samples.size());
328     FOR(i, samples.size())
329     {
330         fvec res = clusterer->Test(samples[i]);
331         float r=0,g=0,b=0;
332         if(res.size() > 1)
333         {
334             FOR(j, res.size())
335             {
336                 r += SampleColor[(j+1)%SampleColorCnt].red()*res[j];
337                 g += SampleColor[(j+1)%SampleColorCnt].green()*res[j];
338                 b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j];
339             }
340         }
341         else if(res.size())
342         {
343             r = (1-res[0])*255 + res[0]* 255;
344             g = (1-res[0])*255;
345             b = (1-res[0])*255;
346         }
347         canvas->sampleColors[i] = QColor(r,g,b);
348     }
349     canvas->maps.model = QPixmap();
350
351         UpdateInfo();
352         drawTimer->clusterer= &this->clusterer;
353         drawTimer->start(QThread::NormalPriority);
354 }
355
356 void MLDemos::ClusterIterate()
357 {
358     if(!canvas || !canvas->data->GetCount()) return;
359     drawTimer->Stop();
360     int tab = optionsCluster->tabWidget->currentIndex();
361     if(tab >= clusterers.size() || !clusterers[tab]) return;
362     QMutexLocker lock(&mutex);
363     if(!clusterer)
364     {
365         clusterer = clusterers[tab]->GetClusterer();
366         tabUsedForTraining = tab;
367     }
368     else clusterers[tab]->SetParams(clusterer);
369     clusterer->SetIterative(true);
370     Train(clusterer);
371     clusterers[tab]->Draw(canvas,clusterer);
372         UpdateInfo();
373 }
374
375 void MLDemos::Maximize()
376 {
377         if(!canvas) return;
378         if(canvas->maps.reward.isNull()) return;
379         QMutexLocker lock(&mutex);
380         drawTimer->Stop();
381         DEL(clusterer);
382         DEL(regressor);
383         DEL(dynamical);
384         DEL(classifier);
385         DEL(maximizer);
386     DEL(projector);
387     int tab = optionsMaximize->tabWidget->currentIndex();
388         if(tab >= maximizers.size() || !maximizers[tab]) return;
389         maximizer = maximizers[tab]->GetMaximizer();
390         maximizer->maxAge = optionsMaximize->iterationsSpin->value();
391         maximizer->stopValue = optionsMaximize->stoppingSpin->value();
392         tabUsedForTraining = tab;
393         Train(maximizer);
394
395         UpdateInfo();
396         drawTimer->Stop();
397         drawTimer->Clear();
398         drawTimer->start(QThread::NormalPriority);
399 }
400
401 void MLDemos::MaximizeContinue()
402 {
403         if(!canvas || !maximizer) return;
404         QMutexLocker lock(&mutex);
405         if(drawTimer)
406         {
407                 drawTimer->Stop();
408         }
409         maximizer->SetConverged(!maximizer->hasConverged());
410
411         UpdateInfo();
412         if(drawTimer)
413         {
414                 drawTimer->start(QThread::NormalPriority);
415         }
416 }
417
418 void MLDemos::Project()
419 {
420     if(!canvas) return;
421     QMutexLocker lock(&mutex);
422     drawTimer->Stop();
423     DEL(clusterer);
424     DEL(regressor);
425     DEL(dynamical);
426     DEL(classifier);
427     DEL(maximizer);
428     DEL(projector);
429     int tab = optionsProject->tabWidget->currentIndex();
430     if(tab >= projectors.size() || !projectors[tab]) return;
431     projector = projectors[tab]->GetProjector();
432     projectors[tab]->SetParams(projector);
433     tabUsedForTraining = tab;
434     bool bHasSource = false;
435     if(sourceData.size() && sourceData.size() == canvas->data->GetCount())
436     {
437         bHasSource = true;
438         canvas->data->SetSamples(sourceData);
439         canvas->data->SetLabels(sourceLabels);
440     }
441     Train(projector);
442     if(!bHasSource)
443     {
444         sourceData = canvas->data->GetSamples();
445         sourceLabels = canvas->data->GetLabels();
446     }
447     projectedData = projector->GetProjected();
448     if(projectedData.size())
449     {
450         canvas->data->SetSamples(projectedData);
451         canvas->data->bProjected = true;
452     }
453     QPixmap infoPixmap;
454     QPainter painter(&infoPixmap);
455     projectors[tab]->DrawInfo(canvas, painter, projector);
456     canvas->FitToData();
457     CanvasTypeChanged();
458     CanvasZoomChanged();
459     canvas->repaint();
460     UpdateInfo();
461     if(drawTimer->isRunning())
462     {
463         drawTimer->Stop();
464         drawTimer->Clear();
465     }
466 }
467
468 void MLDemos::ProjectRevert()
469 {
470     if(!sourceData.size()) return;
471     canvas->data->SetSamples(sourceData);
472     canvas->data->SetLabels(sourceLabels);
473     canvas->data->bProjected = false;
474     canvas->FitToData();
475     CanvasTypeChanged();
476     CanvasZoomChanged();
477     canvas->repaint();
478     UpdateInfo();
479     if(drawTimer->isRunning())
480     {
481         drawTimer->Stop();
482         drawTimer->Clear();
483     }
484     sourceData.clear();
485     sourceLabels.clear();
486 }
487
488 void MLDemos::ProjectReproject()
489 {
490     if(!canvas) return;
491     QMutexLocker lock(&mutex);
492     drawTimer->Stop();
493     DEL(clusterer);
494     DEL(regressor);
495     DEL(dynamical);
496     DEL(classifier);
497     DEL(maximizer);
498     DEL(projector);
499     int tab = optionsProject->tabWidget->currentIndex();
500     if(tab >= projectors.size() || !projectors[tab]) return;
501     projector = projectors[tab]->GetProjector();
502     projectors[tab]->SetParams(projector);
503     tabUsedForTraining = tab;
504     Train(projector);
505     sourceData = canvas->data->GetSamples();
506     sourceLabels = canvas->data->GetLabels();
507     projectedData = projector->GetProjected();
508     if(projectedData.size())
509     {
510         canvas->data->SetSamples(projectedData);
511         canvas->data->bProjected = true;
512     }
513     QPixmap infoPixmap;
514     QPainter painter(&infoPixmap);
515     projectors[tab]->DrawInfo(canvas, painter, projector);
516     canvas->FitToData();
517     CanvasTypeChanged();
518     CanvasZoomChanged();
519     canvas->repaint();
520
521     UpdateInfo();
522     if(drawTimer->isRunning())
523     {
524         drawTimer->Stop();
525         drawTimer->Clear();
526     }
527 }
528
529 void MLDemos::ExportOutput()
530 {
531     if(!classifier && !regressor && !clusterer && !dynamical && !maximizer) return;
532     // get a file
533 }
534
535 void MLDemos::ExportAnimation()
536 {
537     if(!canvas->data->GetSamples().size()) return;
538 }
539