REMOVED: the DrawModel function from classifierInterface (they all do exactly the...
[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 "drawUtils.h"
28 #include "roc.h"
29 #include <algorithm>
30 #include <QDebug>
31 #include <fstream>
32 #include <QPixmap>
33 #include <QBitmap>
34 #include <QSettings>
35 #include <QMutexLocker>
36 #include <QFileDialog>
37 #include <QProgressDialog>
38 #include <qcontour.h>
39 #include <glUtils.h>
40
41 using namespace std;
42
43 void MLDemos::Classify()
44 {
45     if(!canvas || !canvas->data->GetCount()) return;
46     drawTimer->Stop();
47     drawTimer->Clear();
48     mutex.lock();
49     DEL(clusterer);
50     DEL(regressor);
51     DEL(dynamical);
52     if(!classifierMulti.size()) DEL(classifier);
53     classifier = 0;
54     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
55     DEL(maximizer);
56     DEL(reinforcement);
57     DEL(projector);
58     lastTrainingInfo = "";
59     if(!optionsClassify->algoList->count()) return;
60     int tab = optionsClassify->algoList->currentIndex();
61     if(tab >= classifiers.size() || !classifiers[tab]) return;
62
63     classifier = classifiers[tab]->GetClassifier();
64     tabUsedForTraining = tab;
65     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
66     int ratioIndex = optionsClassify->traintestRatioCombo->currentIndex();
67     float trainRatio = ratios[ratioIndex];
68     int positive = optionsClassify->positiveSpin->value();
69     vector<bool> trainList;
70     if(optionsClassify->manualTrainButton->isChecked())
71     {
72         // we get the list of samples that are checked
73         trainList = GetManualSelection();
74     }
75
76     bool trained = Train(classifier, positive, trainRatio, trainList);
77     if(trained)
78     {
79         classifiers[tab]->Draw(canvas, classifier);
80         DrawClassifiedSamples(canvas, classifier, classifierMulti);
81         glw->clearLists();
82         if(canvas->canvasType == 1)
83         {
84             classifiers[tab]->DrawGL(canvas, glw, classifier);
85             if(canvas->data->GetDimCount() == 3) Draw3DClassifier(glw, classifier);
86         }
87
88         UpdateInfo();
89         qDebug() << "using draw timer" << classifier->UsesDrawTimer();
90         if(drawTimer && classifier->UsesDrawTimer())
91         {
92             drawTimer->start(QThread::NormalPriority);
93         }
94         if(canvas->canvasType) CanvasOptionsChanged();
95         // we fill in the canvas sampleColors
96         vector<fvec> samples = canvas->data->GetSamples();
97         canvas->sampleColors.resize(samples.size());
98         FOR(i, samples.size())
99         {
100             canvas->sampleColors[i] = DrawTimer::GetColor(classifier, samples[i], &classifierMulti);
101         }
102         if(canvas->canvasType)
103         {
104             canvas->maps.model = QPixmap();
105             CanvasOptionsChanged();
106         }
107         canvas->repaint();
108     }
109     else
110     {
111         mutex.unlock();
112         Clear();
113         mutex.lock();
114         UpdateInfo();
115     }
116     mutex.unlock();
117 }
118
119 vector<bool> MLDemos::GetManualSelection()
120 {
121     vector<bool> trainList;
122     if(!canvas || !canvas->data->GetCount()) return trainList;
123     trainList.resize(manualSelection->sampleList->count(), false);
124     QList<QListWidgetItem*> selected = manualSelection->sampleList->selectedItems();
125     if(!selected.size()) // if nothing is selected we use all samples as training
126     {
127         trainList = vector<bool>(canvas->data->GetCount(), true);
128         return trainList;
129     }
130     FOR(i, selected.size())
131     {
132         int index = manualSelection->sampleList->row(selected[i]);
133         trainList[index] = true;
134     }
135     return trainList;
136 }
137
138 ivec MLDemos::GetInputDimensions()
139 {
140     if(!canvas || !canvas->data->GetCount()) return ivec();
141     QList<QListWidgetItem*> selected = inputDimensions->dimList->selectedItems();
142     if(!selected.size() || selected.size() == inputDimensions->dimList->count()) return ivec(); // if nothing is selected we use all dimensions for training
143     ivec dimList(selected.size());
144     FOR(i, selected.size())
145     {
146         dimList[i] = inputDimensions->dimList->row(selected[i]);
147     }
148     return dimList;
149 }
150
151 void MLDemos::Regression()
152 {
153     if(!canvas || !canvas->data->GetCount()) return;
154     drawTimer->Stop();
155     drawTimer->Clear();
156
157     QMutexLocker lock(&mutex);
158     DEL(clusterer);
159     DEL(regressor);
160     DEL(dynamical);
161     if(!classifierMulti.size()) DEL(classifier);
162     classifier = 0;
163     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
164     DEL(maximizer);
165     DEL(reinforcement);
166     DEL(projector);
167     lastTrainingInfo = "";
168     if(!optionsRegress->algoList->count()) return;
169     int tab = optionsRegress->algoList->currentIndex();
170     if(tab >= regressors.size() || !regressors[tab]) return;
171     int outputDim = optionsRegress->outputDimCombo->currentIndex();
172     ivec inputDims = GetInputDimensions();
173     //ivec inputDims = optionsRegress->inputDimButton->isChecked() ? GetInputDimensions() : ivec();
174     if(inputDims.size()==1 && inputDims[0] == outputDim) return;
175
176     int outputIndexInList = -1;
177     FOR(i, inputDims.size()) if(outputDim == inputDims[i])
178     {
179         outputIndexInList = i;
180         break;
181     }
182     if(outputDim != -1)
183     {
184         if(canvas->canvasType == 1)
185         {
186             //ui.canvasX3Spin->setValue(outputDim+1);
187         }
188         else if(canvas->canvasType == 0)
189         {
190             ui.canvasX2Spin->setValue(outputDim+1);
191         }
192         DisplayOptionsChanged();
193     }
194
195     regressor = regressors[tab]->GetRegressor();
196     tabUsedForTraining = tab;
197
198     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
199     int ratioIndex = optionsRegress->traintestRatioCombo->currentIndex();
200     float trainRatio = ratios[ratioIndex];
201
202     vector<bool> trainList;
203     if(optionsRegress->manualTrainButton->isChecked())
204     {
205         // we get the list of samples that are checked
206         trainList = GetManualSelection();
207     }
208
209     Train(regressor, outputDim, trainRatio, trainList);
210     regressors[tab]->Draw(canvas, regressor);
211     glw->clearLists();
212     if(canvas->canvasType == 1)
213     {
214         regressors[tab]->DrawGL(canvas, glw, regressor);
215         // here we compute the regression plane for 3D datasets
216         if(canvas->data->GetDimCount() == 3) Draw3DRegressor(glw, regressor);
217     }
218     // here we draw the errors for each sample
219     if(canvas->data->GetDimCount() > 2 && canvas->canvasType == 0)
220     {
221         vector<fvec> samples = canvas->data->GetSamples();
222         vector<fvec> subsamples = canvas->data->GetSampleDims(inputDims, outputIndexInList==-1 ? outputDim : -1);
223         ivec labels = canvas->data->GetLabels();
224         QPainter painter(&canvas->maps.model);
225         painter.setRenderHint(QPainter::Antialiasing);
226         // we draw the starting sample
227         painter.setOpacity(0.4);
228         painter.setPen(Qt::black);
229         painter.setBrush(Qt::white);
230         FOR(i, samples.size())
231         {
232             fvec sample = samples[i];
233             QPointF point = canvas->toCanvasCoords(sample);
234             painter.drawEllipse(point, 6,6);
235         }
236         // we draw the estimated sample
237         painter.setPen(Qt::white);
238         painter.setBrush(Qt::black);
239         FOR(i, samples.size())
240         {
241             fvec sample = samples[i];
242             fvec estimate = regressor->Test(subsamples[i]);
243             sample[outputDim] = estimate[0];
244             QPointF point2 = canvas->toCanvasCoords(sample);
245             painter.drawEllipse(point2, 5,5);
246         }
247         painter.setOpacity(1);
248         // we draw the error bars
249         FOR(i, samples.size())
250         {
251             fvec sample = samples[i];
252             fvec estimate = regressor->Test(subsamples[i]);
253             QPointF point = canvas->toCanvasCoords(sample);
254             sample[outputDim] = estimate[0];
255             QPointF point2 = canvas->toCanvasCoords(sample);
256             QColor color = SampleColor[labels[i]%SampleColorCnt];
257             if(!labels[i]) color = Qt::black;
258             painter.setPen(QPen(color, 1));
259             painter.drawLine(point, point2);
260         }
261     }
262     UpdateInfo();
263 }
264
265 void MLDemos::Dynamize()
266 {
267     if(!canvas || !canvas->data->GetCount() || !canvas->data->GetSequences().size()) return;
268     drawTimer->Stop();
269     drawTimer->Clear();
270     QMutexLocker lock(&mutex);
271     DEL(clusterer);
272     DEL(regressor);
273     DEL(dynamical);
274     if(!classifierMulti.size()) DEL(classifier);
275     classifier = 0;
276     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
277     DEL(maximizer);
278     DEL(reinforcement);
279     DEL(projector);
280     lastTrainingInfo = "";
281     if(!optionsDynamic->algoList->count()) return;
282     int tab = optionsDynamic->algoList->currentIndex();
283     if(tab >= dynamicals.size() || !dynamicals[tab]) return;
284     dynamical = dynamicals[tab]->GetDynamical();
285     tabUsedForTraining = tab;
286
287     Train(dynamical);
288     dynamicals[tab]->Draw(canvas,dynamical);
289     glw->clearLists();
290     if(canvas->canvasType == 1)
291     {
292         dynamicals[tab]->DrawGL(canvas, glw, dynamical);
293         if(canvas->data->GetDimCount() == 3)
294         {
295             int displayStyle = optionsDynamic->displayCombo->currentIndex();
296             if(displayStyle == 3) // DS animation
297             {
298             }
299             else Draw3DDynamical(glw, dynamical, displayStyle);
300         }
301     }
302
303     int w = canvas->width(), h = canvas->height();
304
305     int resampleType = optionsDynamic->resampleCombo->currentIndex();
306     int resampleCount = optionsDynamic->resampleSpin->value();
307     int centerType = optionsDynamic->centerCombo->currentIndex();
308     float dT = optionsDynamic->dtSpin->value();
309     int zeroEnding = optionsDynamic->zeroCheck->isChecked();
310     bool bColorMap = optionsDynamic->colorCheck->isChecked();
311
312     // we draw the current trajectories
313     vector< vector<fvec> > trajectories = canvas->data->GetTrajectories(resampleType, resampleCount, centerType, dT, zeroEnding);
314     vector< vector<fvec> > testTrajectories;
315     int steps = 300;
316     if(trajectories.size())
317     {
318         testTrajectories.resize(trajectories.size());
319         int dim = trajectories[0][0].size() / 2;
320         FOR(i, trajectories.size())
321         {
322             fvec start(dim,0);
323             FOR(d, dim) start[d] = trajectories[i][0][d];
324             vector<fvec> result = dynamical->Test(start, steps);
325             testTrajectories[i] = result;
326         }
327         canvas->maps.model = QPixmap(w,h);
328         QBitmap bitmap(w,h);
329         bitmap.clear();
330         canvas->maps.model.setMask(bitmap);
331         canvas->maps.model.fill(Qt::transparent);
332
333         if(canvas->canvasType == 0) // standard canvas
334         {
335             /*
336             QPainter painter(&canvas->maps.model);
337             painter.setRenderHint(QPainter::Antialiasing);
338             FOR(i, testTrajectories.size())
339             {
340                 vector<fvec> &result = testTrajectories[i];
341                 fvec oldPt = result[0];
342                 int count = result.size();
343                 FOR(j, count-1)
344                 {
345                     fvec pt = result[j+1];
346                     painter.setPen(QPen(Qt::green, 2));
347                     painter.drawLine(canvas->toCanvasCoords(pt), canvas->toCanvasCoords(oldPt));
348                     oldPt = pt;
349                 }
350                 painter.setBrush(Qt::NoBrush);
351                 painter.setPen(Qt::green);
352                 painter.drawEllipse(canvas->toCanvasCoords(result[0]), 5, 5);
353                 painter.setPen(Qt::red);
354                 painter.drawEllipse(canvas->toCanvasCoords(result[count-1]), 5, 5);
355             }
356             */
357         }
358         else
359         {
360             //pair<fvec,fvec> bounds = canvas->data->GetBounds();
361             //Expose::DrawTrajectories(canvas->maps.model, testTrajectories, vector<QColor>(), canvas->canvasType-1, 1, bounds);
362         }
363     }
364
365     // the first index is "none", so we subtract 1
366     int avoidIndex = optionsDynamic->obstacleCombo->currentIndex()-1;
367     if(avoidIndex >=0 && avoidIndex < avoiders.size() && avoiders[avoidIndex])
368     {
369         DEL(dynamical->avoid);
370         dynamical->avoid = avoiders[avoidIndex]->GetObstacleAvoidance();
371     }
372     UpdateInfo();
373
374     //Draw2DDynamical(canvas, dynamical);
375     if(dynamicals[tab]->UsesDrawTimer())
376     {
377         drawTimer->bColorMap = bColorMap;
378         drawTimer->start(QThread::NormalPriority);
379     }
380 }
381
382 void MLDemos::Avoidance()
383 {
384     if(!canvas || !dynamical) return;
385     if(!optionsDynamic->obstacleCombo->count()) return;
386     drawTimer->Stop();
387     QMutexLocker lock(&mutex);
388     // the first index is "none", so we subtract 1
389     int index = optionsDynamic->obstacleCombo->currentIndex()-1;
390     if(index >=0 && index >= avoiders.size() || !avoiders[index]) return;
391     DEL(dynamical->avoid);
392     dynamical->avoid = avoiders[index]->GetObstacleAvoidance();
393     UpdateInfo();
394     drawTimer->Clear();
395     drawTimer->start(QThread::NormalPriority);
396 }
397
398 fvec ClusterMetrics(std::vector<fvec> samples, ivec labels, std::vector<fvec> scores, float ratio = 1.f)
399 {
400     fvec results(4, 0);
401     results[0] = drand48();
402     if(!samples.size() || !scores.size()) return results;
403     int dim = samples[0].size();
404     int nbClusters = scores[0].size();
405     int count = samples.size();
406     // compute bic
407     double loglik = 0;
408
409     vector<fvec> means(nbClusters);
410     FOR(k, nbClusters)
411     {
412         means[k] = fvec(dim, 0);
413         float contrib = 0;
414         FOR(i, count)
415         {
416             contrib += scores[i][k];
417             means[k] += samples[i]*scores[i][k];
418         }
419         means[k] /= contrib;
420     }
421
422     float log_lik=0;
423     float like;
424     float *pxi = new float[nbClusters];
425     int data_i=0;
426     int state_i;
427
428     fvec loglikes(nbClusters);
429     FOR(k, nbClusters)
430     {
431         float rss = 0;
432         double contrib = 0;
433         FOR(i, count)
434         {
435             contrib += scores[i][k];
436             if(contrib==0) continue;
437             fvec diff = samples[i]-means[k];
438             rss += diff*diff*scores[i][k];
439         }
440         loglikes[k] = rss;
441     }
442     FOR(k, nbClusters) loglik += loglikes[k];
443     //loglik /= nbClusters;
444
445     results[0] = loglik; // RSS
446     results[1] = log(count)*nbClusters + loglik; // BIC
447     results[2] = 2*nbClusters + loglik; // AIC
448
449
450     // we compute the f-measures for each class
451     map<int,int> classcounts;
452     int cnt = 0;
453     FOR(i, labels.size()) if(!classcounts.count(labels[i])) classcounts[labels[i]] = cnt++;
454     int classCount = classcounts.size();
455     map<int, fvec> classScores;
456     fvec clusterScores(nbClusters);
457     map<int,float> labelScores;
458
459     if(ratio == 1.f)
460     {
461         FOR(i, labels.size())
462         {
463             labelScores[labels[i]] += 1.f;
464             if(!classScores.count(labels[i]))classScores[labels[i]].resize(nbClusters);
465             FOR(k, nbClusters)
466             {
467                 classScores[labels[i]][k] += scores[i][k];
468                 clusterScores[k] += scores[i][k];
469             }
470         }
471     }
472     else
473     {
474         u32 *perm = randPerm(labels.size());
475         map<int, ivec> indices;
476         FOR(i, labels.size()) indices[labels[perm[i]]].push_back(perm[i]);
477         for(map<int,ivec>::iterator it = indices.begin(); it != indices.end(); it++)
478         {
479             int labelCount = max(1,int(it->second.size()*ratio));
480             FOR(i, labelCount)
481             {
482                 labelScores[labels[it->second[i]]] += 1.f;
483                 if(!classScores.count(labels[it->second[i]]))classScores[labels[it->second[i]]].resize(nbClusters);
484                 FOR(k, nbClusters)
485                 {
486                     classScores[labels[it->second[i]]][k] += scores[it->second[i]][k];
487                     clusterScores[k] += scores[it->second[i]][k];
488                 }
489             }
490         }
491         delete [] perm;
492     }
493
494     float fmeasure = 0;
495     map<int,float>::iterator it2 = labelScores.begin();
496     for(map<int,fvec>::iterator it = classScores.begin(); it != classScores.end(); it++, it2++)
497     {
498         float maxScore = -FLT_MAX;
499         FOR(k, nbClusters)
500         {
501             float precision = it->second[k] / it2->second;
502             float recall = it->second[k] / clusterScores[k];
503             float f1 = 2*precision*recall/(precision+recall);
504             maxScore = max(maxScore,f1);
505         }
506         fmeasure += maxScore;
507     }
508     int classAndClusterCount = classCount;
509     // we penalize empty clusters
510     FOR(k, nbClusters) if(clusterScores[k] == 0) classAndClusterCount++; // we have an empty cluster!
511     fmeasure /= classAndClusterCount;
512
513     results[3] = -fmeasure; // F-Measure
514
515     return results;
516 }
517
518
519 void MLDemos::Cluster()
520 {
521     if(!canvas || !canvas->data->GetCount()) return;
522     drawTimer->Stop();
523     QMutexLocker lock(&mutex);
524     DEL(clusterer);
525     DEL(regressor);
526     DEL(dynamical);
527     if(!classifierMulti.size()) DEL(classifier);
528     classifier = 0;
529     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
530     DEL(maximizer);
531     DEL(reinforcement);
532     DEL(projector);
533     lastTrainingInfo = "";
534     if(!optionsCluster->algoList->count()) return;
535     int tab = optionsCluster->algoList->currentIndex();
536     if(tab >= clusterers.size() || !clusterers[tab]) return;
537     clusterer = clusterers[tab]->GetClusterer();
538     tabUsedForTraining = tab;
539     vector<bool> trainList;
540     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
541     int ratioIndex = optionsCluster->trainTestCombo->currentIndex();
542     float trainRatio = ratios[ratioIndex];
543
544     if(optionsCluster->manualTrainButton->isChecked())
545     {
546         // we get the list of samples that are checked
547         trainList = GetManualSelection();
548     }
549
550     float testError;
551     Train(clusterer, trainRatio, trainList, &testError);
552     drawTimer->Stop();
553     drawTimer->Clear();
554     clusterers[tab]->Draw(canvas,clusterer);
555     glw->clearLists();
556     if(canvas->canvasType == 1)
557     {
558         clusterers[tab]->DrawGL(canvas, glw, clusterer);
559         if(canvas->data->GetDimCount() == 3) Draw3DClusterer(glw, clusterer);
560     }
561
562
563     // we compute the stats on the clusters (f-measure, bic etc)
564
565     vector<fvec> samples = canvas->data->GetSamples();
566     ivec labels = canvas->data->GetLabels();
567     vector<fvec> clusterScores(samples.size());
568     FOR(i, canvas->data->GetCount())
569     {
570         fvec result = clusterer->Test(samples[i]);
571         if(clusterer->NbClusters()==1) clusterScores[i] = result;
572         else if(result.size()>1) clusterScores[i] = result;
573         else if(result.size())
574         {
575             fvec res(clusterer->NbClusters(),0);
576             res[result[0]] = 1.f;
577         }
578     }
579
580     int f1ratioIndex = optionsCluster->trainRatioCombo->currentIndex();
581     float f1ratios[] = {0.01f, 0.05f, 0.1f, 0.2f, 1.f/3.f, 0.5f, 0.75f, 1.f};
582     float f1ratio = f1ratios[f1ratioIndex];
583
584     fvec clusterMetrics = ClusterMetrics(samples, labels, clusterScores, f1ratio);
585
586     optionsCluster->resultList->clear();
587     optionsCluster->resultList->addItem(QString("rss: %1").arg(clusterMetrics[0], 0, 'f', 2));
588     optionsCluster->resultList->addItem(QString("bic: %1").arg(clusterMetrics[1], 0, 'f', 2));
589     optionsCluster->resultList->addItem(QString("aic: %1").arg(clusterMetrics[2], 0, 'f', 2));
590     optionsCluster->resultList->addItem(QString("f1: %1").arg(clusterMetrics[3], 0, 'f', 2));
591     FOR(i, clusterMetrics.size())
592     {
593         optionsCluster->resultList->item(i)->setForeground(i ? SampleColor[i%SampleColorCnt] : Qt::gray);
594     }
595
596     // we fill in the canvas sampleColors for the alternative display types
597     canvas->sampleColors.resize(samples.size());
598     FOR(i, samples.size())
599     {
600         fvec res = clusterer->Test(samples[i]);
601         float r=0,g=0,b=0;
602         if(res.size() > 1)
603         {
604             FOR(j, res.size())
605             {
606                 r += SampleColor[(j+1)%SampleColorCnt].red()*res[j];
607                 g += SampleColor[(j+1)%SampleColorCnt].green()*res[j];
608                 b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j];
609             }
610         }
611         else if(res.size())
612         {
613             r = (1-res[0])*255 + res[0]* 255;
614             g = (1-res[0])*255;
615             b = (1-res[0])*255;
616         }
617         canvas->sampleColors[i] = QColor(r,g,b);
618     }
619     canvas->maps.model = QPixmap();
620     canvas->repaint();
621
622     UpdateInfo();
623     QString infoText = showStats->infoText->text();
624     infoText += "\nClustering as Classifier\n";
625     infoText += QString("F-Measure: %1\n").arg(testError, 0, 'f', 3);
626     showStats->infoText->setText(infoText);
627
628     drawTimer->clusterer= &this->clusterer;
629     drawTimer->start(QThread::NormalPriority);
630 }
631
632 void MLDemos::ClusterTest()
633 {
634     if(!canvas || !canvas->data->GetCount()) return;
635     drawTimer->Stop();
636     drawTimer->Clear();
637     QMutexLocker lock(&mutex);
638     DEL(clusterer);
639     DEL(regressor);
640     DEL(dynamical);
641     if(!classifierMulti.size()) DEL(classifier);
642     classifier = 0;
643     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
644     DEL(maximizer);
645     DEL(reinforcement);
646     DEL(projector);
647     lastTrainingInfo = "";
648     if(!optionsCluster->algoList->count()) return;
649     int tab = optionsCluster->algoList->currentIndex();
650     if(tab >= clusterers.size() || !clusterers[tab]) return;
651     clusterer = clusterers[tab]->GetClusterer();
652     tabUsedForTraining = tab;
653
654     int startCount=optionsCluster->rangeStartSpin->value(), stopCount=optionsCluster->rangeStopSpin->value();
655     if(startCount>stopCount) startCount ^= stopCount ^= startCount ^= stopCount;
656
657     vector<fvec> samples = canvas->data->GetSamples();
658     ivec labels = canvas->data->GetLabels();
659     int f1ratioIndex = optionsCluster->trainRatioCombo->currentIndex();
660     float f1ratios[] = {0.01f, 0.05f, 0.1f, 0.2f, 1.f/3.f, 0.5f, 0.75f, 1.f};
661     float ratio = f1ratios[f1ratioIndex];
662
663     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
664     int ratioIndex = optionsCluster->trainTestCombo->currentIndex();
665     float trainRatio = ratios[ratioIndex];
666
667     vector<bool> trainList;
668     if(optionsCluster->manualTrainButton->isChecked())
669     {
670         // we get the list of samples that are checked
671         trainList = GetManualSelection();
672     }
673
674     float testError = 0;
675     int crossValCount = 5;
676     fvec testErrors(crossValCount);
677
678     FOR(j, crossValCount)
679     {
680         Train(clusterer, trainRatio, trainList, &testError);
681         testErrors[j] = testError;
682     }
683
684     // we fill in the canvas sampleColors for the alternative display types
685     canvas->sampleColors.resize(samples.size());
686     FOR(i, samples.size())
687     {
688         fvec res = clusterer->Test(samples[i]);
689         float r=0,g=0,b=0;
690         if(res.size() > 1)
691         {
692             FOR(j, res.size())
693             {
694                 r += SampleColor[(j+1)%SampleColorCnt].red()*res[j];
695                 g += SampleColor[(j+1)%SampleColorCnt].green()*res[j];
696                 b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j];
697             }
698         }
699         else if(res.size())
700         {
701             r = (1-res[0])*255 + res[0]* 255;
702             g = (1-res[0])*255;
703             b = (1-res[0])*255;
704         }
705         canvas->sampleColors[i] = QColor(r,g,b);
706     }
707     canvas->maps.model = QPixmap();
708     clusterers[tab]->Draw(canvas, clusterer);
709     glw->clearLists();
710     if(canvas->canvasType == 1)
711     {
712         clusterers[tab]->DrawGL(canvas, glw, clusterer);
713         if(canvas->data->GetDimCount() == 3) Draw3DClusterer(glw, clusterer);
714     }
715
716
717     UpdateInfo();
718     QString infoText = showStats->infoText->text();
719     infoText += "\nClustering as Classifier\nF-Measures:\n";
720
721     float mean=0, stdev=0;
722     FOR(j, testErrors.size()) mean += testErrors[j];
723     mean /= testErrors.size();
724     FOR(j, testErrors.size()) stdev += (testErrors[j] - mean)*(testErrors[j] - mean);
725     stdev /= testErrors.size();
726     stdev = sqrtf(stdev);
727     infoText += QString("%1 clusters: %2 (+- %3)\n").arg(clusterer->NbClusters()).arg(mean, 0, 'f', 3).arg(stdev, 0, 'f', 3);
728
729     showStats->infoText->setText(infoText);
730     showStats->tabWidget->setCurrentIndex(1); // we show the info panel
731     statsDialog->show();
732
733     drawTimer->clusterer= &this->clusterer;
734     drawTimer->start(QThread::NormalPriority);
735     canvas->repaint();
736 }
737
738 void MLDemos::ClusterOptimize()
739 {
740     if(!canvas || !canvas->data->GetCount()) return;
741     drawTimer->Stop();
742     drawTimer->Clear();
743     QMutexLocker lock(&mutex);
744     DEL(clusterer);
745     DEL(regressor);
746     DEL(dynamical);
747     if(!classifierMulti.size()) DEL(classifier);
748     classifier = 0;
749     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
750     DEL(maximizer);
751     DEL(reinforcement);
752     DEL(projector);
753     lastTrainingInfo = "";
754     if(!optionsCluster->algoList->count()) return;
755     int tab = optionsCluster->algoList->currentIndex();
756     if(tab >= clusterers.size() || !clusterers[tab]) return;
757     clusterer = clusterers[tab]->GetClusterer();
758     tabUsedForTraining = tab;
759
760     int startCount=optionsCluster->rangeStartSpin->value(), stopCount=optionsCluster->rangeStopSpin->value();
761     if(startCount>stopCount) startCount ^= stopCount ^= startCount ^= stopCount;
762
763     vector<fvec> samples = canvas->data->GetSamples();
764     ivec labels = canvas->data->GetLabels();
765     int f1ratioIndex = optionsCluster->trainRatioCombo->currentIndex();
766     float f1ratios[] = {0.01f, 0.05f, 0.1f, 0.2f, 1.f/3.f, 0.5f, 0.75f, 1.f};
767     float ratio = f1ratios[f1ratioIndex];
768
769     float ratios [] = {.1f,.25f,1.f/3.f,.5f,2.f/3.f,.75f,.9f,1.f};
770     int ratioIndex = optionsCluster->trainTestCombo->currentIndex();
771     float trainRatio = ratios[ratioIndex];
772
773     vector<bool> trainList;
774     if(optionsCluster->manualTrainButton->isChecked())
775     {
776         // we get the list of samples that are checked
777         trainList = GetManualSelection();
778     }
779
780     float testError = 0;
781     ivec kCounts;
782     vector< vector<fvec> > resultList(4);
783     vector<fvec> testErrors(stopCount-startCount+1);
784     int crossValCount = 5;
785     FOR(i, resultList.size()) resultList[i].resize(crossValCount);
786     for(int k=startCount; k<=stopCount; k++)
787     {
788         clusterer->SetNbClusters(k);
789         testErrors[k-startCount].resize(crossValCount);
790         FOR(j, crossValCount)
791         {
792             Train(clusterer, trainRatio, trainList, &testError);
793             testErrors[k-startCount][j] = testError;
794
795             int folds = 10;
796             fvec metricMeans(resultList.size());
797             ivec foldCount(resultList.size());
798             FOR(f, folds)
799             {
800                 vector<fvec> clusterScores(samples.size());
801                 FOR(i, canvas->data->GetCount())
802                 {
803                     fvec result = clusterer->Test(samples[i]);
804                     if(clusterer->NbClusters()==1) clusterScores[i] = result;
805                     else if(result.size()>1) clusterScores[i] = result;
806                     else if(result.size())
807                     {
808                         fvec res(clusterer->NbClusters(),0);
809                         res[result[0]] = 1.f;
810                     }
811                 }
812                 fvec clusterMetrics = ClusterMetrics(samples, labels, clusterScores, ratio);
813                 FOR(d, clusterMetrics.size())
814                 {
815                     if(clusterMetrics[d] != clusterMetrics[d]) continue; // not a number
816                     metricMeans[d] += clusterMetrics[d];
817                     foldCount[d]++;
818                 }
819             }
820             FOR(d, metricMeans.size()) metricMeans[d] /= foldCount[d];
821             FOR(i, metricMeans.size())
822             {
823                 resultList[i][j].push_back(metricMeans[i]);
824             }
825         }
826         kCounts.push_back(k);
827     }
828
829     vector<fvec> results(4);
830     FOR(i, resultList.size())
831     {
832         results[i].resize(resultList[i][0].size());
833         FOR(k, resultList[i][0].size())
834         {
835             double value = 0;
836             FOR(j, crossValCount)
837             {
838                 value += resultList[i][j][k];
839             }
840             value /= crossValCount;
841             results[i][k] = value;
842         }
843     }
844
845     int w = optionsCluster->graphLabel->width();
846     int h = optionsCluster->graphLabel->height();
847     int pad = 6;
848     QPixmap pixmap(w,h);
849     QBitmap bitmap(w,h);
850     bitmap.clear();
851     pixmap.setMask(bitmap);
852     pixmap.fill(Qt::transparent);
853     QPainter painter(&pixmap);
854
855     painter.setPen(QPen(Qt::black, 1.f));
856     painter.drawLine(pad, h - 2*pad, w-pad, h-2*pad);
857     painter.drawLine(pad, 0, pad, h-2*pad);
858     QFont font = painter.font();
859     font.setPointSize(9);
860     painter.setFont(font);
861     FOR(k, kCounts.size())
862     {
863         float x = k/(float)(kCounts.size()-1);
864         painter.drawLine(x*(w-2*pad)+pad, h-2*pad-1, x*(w-2*pad)+pad, h-2*pad+1);
865         if(k == kCounts.size()-1) x -= 0.05;
866         painter.drawText(x*(w-2*pad)-2+pad, h-1, QString("%1").arg(kCounts[k]));
867     }
868
869     painter.setRenderHint(QPainter::Antialiasing);
870     fvec mins(results.size(), FLT_MAX), maxes(results.size(), -FLT_MAX);
871     FOR(i, results.size())
872     {
873         FOR(j, results[i].size())
874         {
875             mins[i] = min(mins[i], results[i][j]);
876             maxes[i] = max(maxes[i], results[i][j]);
877         }
878     }
879
880     vector< pair<float,int> > bests(results.size());
881     FOR(i, results.size())
882     {
883         QPointF old;
884         painter.setPen(QPen(i ? SampleColor[i%SampleColorCnt] : Qt::gray,2));
885         bests[i] = make_pair(FLT_MAX, 0);
886         FOR(k, kCounts.size())
887         {
888             if(results[i][k] < bests[i].first)
889             {
890                 bests[i] = make_pair(results[i][k], kCounts[k]);
891             }
892             float x = k/(float)(kCounts.size()-1);
893             float y = (results[i][k] - mins[i])/(maxes[i]-mins[i]);
894             //if(i == 3) y = 1.f - y; // fmeasures needs to be maximized
895             QPointF point(x*(w-2*pad)+pad, (1.f-y)*(h-2*pad));
896             if(k) painter.drawLine(old, point);
897             old = point;
898         }
899     }
900     optionsCluster->graphLabel->setPixmap(pixmap);
901
902     optionsCluster->resultList->clear();
903     optionsCluster->resultList->addItem(QString("rss: %1 (%2)").arg(bests[0].second).arg(bests[0].first, 0, 'f', 2));
904     optionsCluster->resultList->addItem(QString("bic: %1 (%2)").arg(bests[1].second).arg(bests[1].first, 0, 'f', 2));
905     optionsCluster->resultList->addItem(QString("aic: %1 (%2)").arg(bests[2].second).arg(bests[2].first, 0, 'f', 2));
906     optionsCluster->resultList->addItem(QString("f1: %1 (%2)").arg(bests[3].second).arg(bests[3].first, 0, 'f', 2));
907     FOR(i, results.size())
908     {
909         optionsCluster->resultList->item(i)->setForeground(i ? SampleColor[i%SampleColorCnt] : Qt::gray);
910     }
911
912     int bestIndex = optionsCluster->optimizeCombo->currentIndex();
913     clusterer->SetNbClusters(bests[bestIndex].second);
914     Train(clusterer, trainRatio, trainList, &testError);
915
916     // we fill in the canvas sampleColors for the alternative display types
917     canvas->sampleColors.resize(samples.size());
918     FOR(i, samples.size())
919     {
920         fvec res = clusterer->Test(samples[i]);
921         float r=0,g=0,b=0;
922         if(res.size() > 1)
923         {
924             FOR(j, res.size())
925             {
926                 r += SampleColor[(j+1)%SampleColorCnt].red()*res[j];
927                 g += SampleColor[(j+1)%SampleColorCnt].green()*res[j];
928                 b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j];
929             }
930         }
931         else if(res.size())
932         {
933             r = (1-res[0])*255 + res[0]* 255;
934             g = (1-res[0])*255;
935             b = (1-res[0])*255;
936         }
937         canvas->sampleColors[i] = QColor(r,g,b);
938     }
939     canvas->maps.model = QPixmap();
940
941     clusterers[tab]->Draw(canvas, clusterer);
942     glw->clearLists();
943     if(canvas->canvasType == 1)
944     {
945         clusterers[tab]->DrawGL(canvas, glw, clusterer);
946         if(canvas->data->GetDimCount() == 3) Draw3DClusterer(glw, clusterer);
947     }
948
949     UpdateInfo();
950     QString infoText = showStats->infoText->text();
951     infoText += "\nClustering as Classifier\nF-Measures:\n";
952     FOR(i, testErrors.size())
953     {
954         float mean=0, stdev=0;
955         FOR(j, testErrors[i].size()) mean += testErrors[i][j];
956         mean /= testErrors[i].size();
957         FOR(j, testErrors[i].size()) stdev += (testErrors[i][j] - mean)*(testErrors[i][j] - mean);
958         stdev /= testErrors[i].size();
959         stdev = sqrtf(stdev);
960         infoText += QString("%1 clusters: %2 (+- %3)\n").arg(i+1).arg(mean, 0, 'f', 3).arg(stdev, 0, 'f', 3);
961     }
962     showStats->infoText->setText(infoText);
963
964     drawTimer->clusterer= &this->clusterer;
965     drawTimer->start(QThread::NormalPriority);
966     canvas->repaint();
967 }
968
969 void MLDemos::ClusterIterate()
970 {
971     if(!canvas || !canvas->data->GetCount()) return;
972     drawTimer->Stop();
973     int tab = optionsCluster->algoList->currentIndex();
974     if(tab >= clusterers.size() || !clusterers[tab]) return;
975     QMutexLocker lock(&mutex);
976     if(!clusterer)
977     {
978         clusterer = clusterers[tab]->GetClusterer();
979         tabUsedForTraining = tab;
980     }
981     else clusterers[tab]->SetParams(clusterer);
982     clusterer->SetIterative(true);
983     Train(clusterer);
984     clusterers[tab]->Draw(canvas,clusterer);
985     glw->clearLists();
986     if(canvas->canvasType == 1)
987     {
988         clusterers[tab]->DrawGL(canvas, glw, clusterer);
989         if(canvas->data->GetDimCount() == 3) Draw3DClusterer(glw, clusterer);
990     }
991
992
993     // we fill in the canvas sampleColors
994     vector<fvec> samples = canvas->data->GetSamples();
995     canvas->sampleColors.resize(samples.size());
996     FOR(i, samples.size())
997     {
998         fvec res = clusterer->Test(samples[i]);
999         float r=0,g=0,b=0;
1000         if(res.size() > 1)
1001         {
1002             FOR(j, res.size())
1003             {
1004                 r += SampleColor[(j+1)%SampleColorCnt].red()*res[j];
1005                 g += SampleColor[(j+1)%SampleColorCnt].green()*res[j];
1006                 b += SampleColor[(j+1)%SampleColorCnt].blue()*res[j];
1007             }
1008         }
1009         else if(res.size())
1010         {
1011             r = (1-res[0])*255 + res[0]* 255;
1012             g = (1-res[0])*255;
1013             b = (1-res[0])*255;
1014         }
1015         canvas->sampleColors[i] = QColor(r,g,b);
1016     }
1017     canvas->maps.model = QPixmap();
1018     canvas->repaint();
1019
1020     UpdateInfo();
1021 }
1022
1023 void MLDemos::Maximize()
1024 {
1025     if(!canvas) return;
1026     if(canvas->maps.reward.isNull()) return;
1027     QMutexLocker lock(&mutex);
1028     drawTimer->Stop();
1029     DEL(clusterer);
1030     DEL(regressor);
1031     DEL(dynamical);
1032     if(!classifierMulti.size()) DEL(classifier);
1033     classifier = 0;
1034     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
1035     DEL(maximizer);
1036     DEL(reinforcement);
1037     DEL(projector);
1038     lastTrainingInfo = "";
1039     if(!optionsMaximize->algoList->count()) return;
1040     int tab = optionsMaximize->algoList->currentIndex();
1041     if(tab >= maximizers.size() || !maximizers[tab]) return;
1042     maximizer = maximizers[tab]->GetMaximizer();
1043     maximizer->maxAge = optionsMaximize->iterationsSpin->value();
1044     maximizer->stopValue = optionsMaximize->stoppingSpin->value();
1045     tabUsedForTraining = tab;
1046     Train(maximizer);
1047
1048     // we draw the contours for the current maximization
1049     int w = 65;
1050     int h = 65;
1051     int W = canvas->width();
1052     int H = canvas->height();
1053     canvas->maps.info = QPixmap(W, H);
1054     QBitmap bitmap(canvas->width(), canvas->height());
1055     canvas->maps.info.setMask(bitmap);
1056     canvas->maps.info.fill(Qt::transparent);
1057     QPainter painter(&canvas->maps.info);
1058
1059     double *bigData = canvas->data->GetReward()->rewards;
1060     double maxVal = -DBL_MAX;
1061     FOR(i, W*H) maxVal = max(bigData[i], maxVal);
1062     maxVal *= maximizer->stopValue; // used to ensure we have a maximum somewhere
1063     double *data = new double[w*h];
1064     FOR(i, w)
1065     {
1066         FOR(j, h)
1067         {
1068             int I = i*W/(w-1);
1069             int J = j*H/(h-1);
1070             if(I >= W) I = W-1;
1071             if(J >= H) J = H-1;
1072             data[j*w + i] = bigData[J*W + I];
1073         }
1074     }
1075
1076     QContour contour(data, w, h);
1077     contour.bDrawColorbar = false;
1078     contour.plotColor = Qt::black;
1079     contour.plotThickness = 1.5;
1080     contour.style = Qt::DashLine;
1081     //contour.style;
1082     contour.Paint(painter, 10);
1083     // we want to find all the samples that are at maximum value
1084     painter.setPen(QColor(255,255,0));
1085     FOR(i,W)
1086     {
1087         FOR(j,H)
1088         {
1089             if(bigData[j*W + i] >= maxVal)
1090             {
1091                 painter.drawPoint(i,j);
1092             }
1093         }
1094     }
1095
1096     delete [] data;
1097     canvas->repaint();
1098
1099     FOR(i, glw->objects.size())
1100     {
1101         if(glw->objects[i].objectType.contains("Maximization"))
1102         {
1103             glw->objects.erase(glw->objects.begin() + i);
1104             i--;
1105         }
1106     }
1107
1108     UpdateInfo();
1109     drawTimer->Stop();
1110     drawTimer->Clear();
1111     drawTimer->start(QThread::NormalPriority);
1112 }
1113
1114 void MLDemos::MaximizeContinue()
1115 {
1116     if(!canvas || !maximizer) return;
1117     QMutexLocker lock(&mutex);
1118     if(drawTimer)
1119     {
1120         drawTimer->Stop();
1121     }
1122     maximizer->SetConverged(!maximizer->hasConverged());
1123
1124     UpdateInfo();
1125     if(drawTimer)
1126     {
1127         drawTimer->start(QThread::NormalPriority);
1128     }
1129 }
1130
1131 void MLDemos::Reinforce()
1132 {
1133     if(!canvas) return;
1134     if(canvas->maps.reward.isNull()) return;
1135     QMutexLocker lock(&mutex);
1136     drawTimer->Stop();
1137     DEL(clusterer);
1138     DEL(regressor);
1139     DEL(dynamical);
1140     if(!classifierMulti.size()) DEL(classifier);
1141     classifier = 0;
1142     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
1143     DEL(maximizer);
1144     DEL(reinforcement);
1145     DEL(projector);
1146     lastTrainingInfo = "";
1147     if(!optionsReinforcement->algoList->count()) return;
1148     int tab = optionsReinforcement->algoList->currentIndex();
1149     if(tab >= reinforcements.size() || !reinforcements[tab]) return;
1150     reinforcement = reinforcements[tab]->GetReinforcement();
1151
1152     reinforcementProblem.problemType = optionsReinforcement->problemCombo->currentIndex();
1153     reinforcementProblem.rewardType = optionsReinforcement->rewardCombo->currentIndex();
1154     reinforcementProblem.policyType = optionsReinforcement->policyCombo->currentIndex();
1155     reinforcementProblem.quantizeType = optionsReinforcement->quantizeCombo->currentIndex();
1156     reinforcementProblem.gridSize = optionsReinforcement->resolutionSpin->value();
1157
1158     reinforcementProblem.simulationSteps = optionsReinforcement->iterationsSpin->value();
1159     reinforcementProblem.displayIterationsCount = optionsReinforcement->displayIterationSpin->value();
1160
1161     reinforcement->maxAge = optionsReinforcement->iterationsSpin->value();
1162
1163     tabUsedForTraining = tab;
1164     Train(reinforcement);
1165     reinforcements[tab]->Draw(canvas, reinforcement);
1166     glw->clearLists();
1167     if(canvas->canvasType == 1)
1168     {
1169         reinforcements[tab]->DrawGL(canvas, glw, reinforcement);
1170         if(canvas->data->GetDimCount() == 3) Draw3DReinforcement(glw, reinforcement);
1171     }
1172
1173     // we draw the contours for the current maximization
1174     int w = 65;
1175     int h = 65;
1176     int W = canvas->width();
1177     int H = canvas->height();
1178     canvas->maps.info = QPixmap(W, H);
1179     QBitmap bitmap(canvas->width(), canvas->height());
1180     canvas->maps.info.setMask(bitmap);
1181     canvas->maps.info.fill(Qt::transparent);
1182     QPainter painter(&canvas->maps.info);
1183
1184     double *bigData = canvas->data->GetReward()->rewards;
1185     double *data = new double[w*h];
1186     FOR(i, w)
1187     {
1188         FOR(j, h)
1189         {
1190             int I = i*W/(w-1);
1191             int J = j*H/(h-1);
1192             if(I >= W) I = W-1;
1193             if(J >= H) J = H-1;
1194             data[j*w + i] = bigData[J*W + I];
1195         }
1196     }
1197
1198     QContour contour(data, w, h);
1199     contour.bDrawColorbar = false;
1200     contour.plotColor = Qt::black;
1201     contour.plotThickness = 1.5;
1202     contour.style = Qt::DashLine;
1203     //contour.style;
1204     contour.Paint(painter, 10);
1205     delete [] data;
1206     canvas->repaint();
1207
1208     UpdateInfo();
1209     drawTimer->Stop();
1210     drawTimer->Clear();
1211     drawTimer->start(QThread::NormalPriority);
1212 }
1213
1214 void MLDemos::ReinforceContinue()
1215 {
1216     if(!canvas || !reinforcement) return;
1217     QMutexLocker lock(&mutex);
1218     if(drawTimer)
1219     {
1220         drawTimer->Stop();
1221     }
1222     reinforcement->SetConverged(!reinforcement->hasConverged());
1223
1224     UpdateInfo();
1225     if(drawTimer)
1226     {
1227         drawTimer->start(QThread::NormalPriority);
1228     }
1229 }
1230
1231 void MLDemos::Project()
1232 {
1233     if(!canvas || !canvas->data->GetCount()) return;
1234     QMutexLocker lock(&mutex);
1235     drawTimer->Stop();
1236     drawTimer->Clear();
1237     DEL(clusterer);
1238     DEL(regressor);
1239     DEL(dynamical);
1240     if(!classifierMulti.size()) DEL(classifier);
1241     classifier = 0;
1242     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
1243     DEL(maximizer);
1244     DEL(reinforcement);
1245     DEL(projector);
1246     lastTrainingInfo = "";
1247     if(!optionsProject->algoList->count()) return;
1248     int tab = optionsProject->algoList->currentIndex();
1249     if(tab >= projectors.size() || !projectors[tab]) return;
1250     projector = projectors[tab]->GetProjector();
1251     projectors[tab]->SetParams(projector);
1252     tabUsedForTraining = tab;
1253     bool bHasSource = false;
1254     if(sourceData.size() && sourceData.size() == canvas->data->GetCount())
1255     {
1256         bHasSource = true;
1257         canvas->data->SetSamples(sourceData);
1258         canvas->data->SetLabels(sourceLabels);
1259     }
1260     vector<bool> trainList;
1261     if(optionsProject->manualTrainButton->isChecked())
1262     {
1263         // we get the list of samples that are checked
1264         trainList = GetManualSelection();
1265     }
1266     Train(projector, trainList);
1267     if(!bHasSource)
1268     {
1269         sourceData = canvas->data->GetSamples();
1270         sourceLabels = canvas->data->GetLabels();
1271     }
1272     projectedData = projector->GetProjected();
1273     if(projectedData.size())
1274     {
1275         canvas->data->SetSamples(projectedData);
1276         canvas->data->bProjected = true;
1277     }
1278     if(optionsProject->fitCheck->isChecked()) canvas->FitToData();
1279     CanvasTypeChanged();
1280     CanvasOptionsChanged();
1281     ResetPositiveClass();
1282     projectors[tab]->Draw(canvas, projector);
1283     glw->clearLists();
1284     if(canvas->canvasType == 1)
1285     {
1286         projectors[tab]->DrawGL(canvas, glw, projector);
1287         if(canvas->data->GetDimCount() == 3) Draw3DProjector(glw, projector);
1288     }
1289     canvas->repaint();
1290     UpdateInfo();
1291 }
1292
1293 void MLDemos::ProjectManifold()
1294 {
1295     if(!canvas || !canvas->data->GetCount()) return;
1296     QMutexLocker lock(&mutex);
1297     drawTimer->Stop();
1298     drawTimer->Clear();
1299     DEL(clusterer);
1300     DEL(regressor);
1301     DEL(dynamical);
1302     if(!classifierMulti.size()) DEL(classifier);
1303     classifier = 0;
1304     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
1305     DEL(maximizer);
1306     DEL(reinforcement);
1307     DEL(projector);
1308     lastTrainingInfo = "";
1309     if(!optionsProject->algoList->count()) return;
1310     int tab = optionsProject->algoList->currentIndex();
1311     if(tab >= projectors.size() || !projectors[tab]) return;
1312     projector = projectors[tab]->GetProjector();
1313     projectors[tab]->SetParams(projector);
1314     tabUsedForTraining = tab;
1315     bool bHasSource = false;
1316     if(sourceData.size() && sourceData.size() == canvas->data->GetCount())
1317     {
1318         bHasSource = true;
1319         canvas->data->SetSamples(sourceData);
1320         canvas->data->SetLabels(sourceLabels);
1321     }
1322     vector<bool> trainList;
1323     if(optionsProject->manualTrainButton->isChecked())
1324     {
1325         // we get the list of samples that are checked
1326         trainList = GetManualSelection();
1327     }
1328     Train(projector, trainList);
1329     if(!bHasSource)
1330     {
1331         sourceData = canvas->data->GetSamples();
1332         sourceLabels = canvas->data->GetLabels();
1333     }
1334     projectedData = projector->GetProjected();
1335
1336     CanvasTypeChanged();
1337     CanvasOptionsChanged();
1338     ResetPositiveClass();
1339     projectors[tab]->Draw(canvas, projector);
1340     glw->clearLists();
1341     if(canvas->canvasType == 1)
1342     {
1343         projectors[tab]->DrawGL(canvas, glw, projector);
1344         if(canvas->data->GetDimCount() == 3) Draw3DProjector(glw, projector);
1345     }
1346     canvas->repaint();
1347     UpdateInfo();
1348 }
1349
1350 void MLDemos::ProjectRevert()
1351 {
1352     QMutexLocker lock(&mutex);
1353     drawTimer->Stop();
1354     drawTimer->Clear();
1355     DEL(clusterer);
1356     DEL(regressor);
1357     DEL(dynamical);
1358     if(!classifierMulti.size()) DEL(classifier);
1359     classifier = 0;
1360     FOR(i,classifierMulti.size()) DEL(classifierMulti[i]); classifierMulti.clear();
1361     DEL(maximizer);
1362     DEL(reinforcement);
1363     DEL(projector);
1364     lastTrainingInfo = "";
1365     if(!sourceData.size()) return;
1366     canvas->data->SetSamples(sourceData);
1367     canvas->data->SetLabels(sourceLabels);
1368     canvas->data->bProjected = false;
1369     canvas->maps.info = QPixmap();
1370     canvas->maps.model = QPixmap();
1371     canvas->maps.confidence = QPixmap();
1372     if(optionsProject->fitCheck->isChecked()) canvas->FitToData();
1373     CanvasTypeChanged();
1374     CanvasOptionsChanged();
1375     ResetPositiveClass();
1376     canvas->repaint();
1377     glw->clearLists();
1378     UpdateInfo();
1379     sourceData.clear();
1380     sourceLabels.clear();
1381 }
1382
1383 void MLDemos::ProjectReproject()
1384 {
1385     if(!canvas || !canvas->data->GetCount()) return;
1386     mutex.lock();
1387     sourceData = canvas->data->GetSamples();
1388     sourceLabels = canvas->data->GetLabels();
1389     mutex.unlock();
1390     Project();
1391 }
1392
1393 void MLDemos::ExportAnimation()
1394 {
1395     if(!canvas->data->GetSamples().size()) return;
1396 }
1397
1398
1399 void MLDemos::UpdateLearnedModel()
1400 {
1401     if(!canvas) return;
1402     if(!clusterer && !regressor && !dynamical && !classifier && !projector) return;
1403     if(glw) glw->clearLists();
1404     if(classifier)
1405     {
1406         QMutexLocker lock(&mutex);
1407         if(glw->isVisible())
1408         {
1409             glw->clearLists();
1410             if(canvas->canvasType == 1)
1411             {
1412                 classifiers[tabUsedForTraining]->DrawGL(canvas, glw, classifier);
1413                 if(canvas->data->GetDimCount() == 3) Draw3DClassifier(glw, classifier);
1414             }
1415         }
1416         else
1417         {
1418             classifiers[tabUsedForTraining]->Draw(canvas, classifier);
1419             DrawClassifiedSamples(canvas, classifier, classifierMulti);
1420             if(classifier->UsesDrawTimer() && !drawTimer->isRunning())
1421             {
1422                 drawTimer->start(QThread::NormalPriority);
1423             }
1424         }
1425     }
1426     if(clusterer)
1427     {
1428         QMutexLocker lock(&mutex);
1429         if(glw->isVisible())
1430         {
1431             glw->clearLists();
1432             if(canvas->canvasType == 1)
1433             {
1434                 clusterers[tabUsedForTraining]->DrawGL(canvas, glw, clusterer);
1435                 if(canvas->data->GetDimCount() == 3) Draw3DClusterer(glw, clusterer);
1436             }
1437         }
1438         else clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
1439     }
1440     if(regressor)
1441     {
1442         QMutexLocker lock(&mutex);
1443         glw->clearLists();
1444         if(canvas->canvasType == 1)
1445         {
1446             regressors[tabUsedForTraining]->DrawGL(canvas, glw, regressor);
1447             if(canvas->data->GetDimCount() == 3) Draw3DRegressor(glw, regressor);
1448         }
1449
1450         regressors[tabUsedForTraining]->Draw(canvas, regressor);
1451         // here we draw the errors for each sample
1452         int outputDim = optionsRegress->outputDimCombo->currentIndex();
1453         ivec inputDims = GetInputDimensions();
1454         //ivec inputDims = optionsRegress->inputDimButton->isChecked() ? GetInputDimensions() : ivec();
1455         if(inputDims.size()==1 && inputDims[0] == outputDim) return;
1456
1457         int outputIndexInList = -1;
1458         FOR(i, inputDims.size()) if(outputDim == inputDims[i])
1459         {
1460             outputIndexInList = i;
1461             break;
1462         }
1463         if(canvas->data->GetDimCount() > 2 && canvas->canvasType == 0)
1464         {
1465             vector<fvec> samples = canvas->data->GetSamples();
1466             vector<fvec> subsamples = canvas->data->GetSampleDims(inputDims, outputIndexInList==-1 ? outputDim : -1);
1467             ivec labels = canvas->data->GetLabels();
1468             QPainter painter(&canvas->maps.model);
1469             painter.setRenderHint(QPainter::Antialiasing);
1470             // we draw the starting sample
1471             painter.setOpacity(0.4);
1472             painter.setPen(Qt::black);
1473             painter.setBrush(Qt::white);
1474             FOR(i, samples.size())
1475             {
1476                 fvec sample = samples[i];
1477                 QPointF point = canvas->toCanvasCoords(sample);
1478                 painter.drawEllipse(point, 6,6);
1479             }
1480             // we draw the estimated sample
1481             painter.setPen(Qt::white);
1482             painter.setBrush(Qt::black);
1483             FOR(i, samples.size())
1484             {
1485                 fvec sample = samples[i];
1486                 fvec estimate = regressor->Test(subsamples[i]);
1487                 sample[outputDim] = estimate[0];
1488                 QPointF point2 = canvas->toCanvasCoords(sample);
1489                 painter.drawEllipse(point2, 5,5);
1490             }
1491             painter.setOpacity(1);
1492             // we draw the error bars
1493             FOR(i, samples.size())
1494             {
1495                 fvec sample = samples[i];
1496                 fvec estimate = regressor->Test(subsamples[i]);
1497                 QPointF point = canvas->toCanvasCoords(sample);
1498                 sample[outputDim] = estimate[0];
1499                 QPointF point2 = canvas->toCanvasCoords(sample);
1500                 QColor color = SampleColor[labels[i]%SampleColorCnt];
1501                 if(!labels[i]) color = Qt::black;
1502                 painter.setPen(QPen(color, 1));
1503                 painter.drawLine(point, point2);
1504             }
1505         }
1506     }
1507     if(dynamical)
1508     {
1509         QMutexLocker lock(&mutex);
1510         if(glw->isVisible())
1511         {
1512             glw->clearLists();
1513             if(canvas->canvasType == 1)
1514             {
1515                 dynamicals[tabUsedForTraining]->DrawGL(canvas, glw, dynamical);
1516                 if(canvas->data->GetDimCount() == 3)
1517                 {
1518                     int displayStyle = optionsDynamic->displayCombo->currentIndex();
1519                     if(displayStyle < 3) Draw3DDynamical(glw, dynamical,displayStyle);
1520                 }
1521             }
1522         }
1523         else
1524         {
1525             dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
1526             int w = canvas->width(), h = canvas->height();
1527
1528             int resampleType = optionsDynamic->resampleCombo->currentIndex();
1529             int resampleCount = optionsDynamic->resampleSpin->value();
1530             int centerType = optionsDynamic->centerCombo->currentIndex();
1531             float dT = optionsDynamic->dtSpin->value();
1532             int zeroEnding = optionsDynamic->zeroCheck->isChecked();
1533             bool bColorMap = optionsDynamic->colorCheck->isChecked();
1534
1535             // we draw the current trajectories
1536             vector< vector<fvec> > trajectories = canvas->data->GetTrajectories(resampleType, resampleCount, centerType, dT, zeroEnding);
1537             vector< vector<fvec> > testTrajectories;
1538             int steps = 300;
1539             if(trajectories.size())
1540             {
1541                 testTrajectories.resize(trajectories.size());
1542                 int dim = trajectories[0][0].size() / 2;
1543                 FOR(i, trajectories.size())
1544                 {
1545                     fvec start(dim,0);
1546                     FOR(d, dim) start[d] = trajectories[i][0][d];
1547                     vector<fvec> result = dynamical->Test(start, steps);
1548                     testTrajectories[i] = result;
1549                 }
1550                 canvas->maps.model = QPixmap(w,h);
1551                 QBitmap bitmap(w,h);
1552                 bitmap.clear();
1553                 canvas->maps.model.setMask(bitmap);
1554                 canvas->maps.model.fill(Qt::transparent);
1555
1556                 if(canvas->canvasType == 0) // standard canvas
1557                 {
1558                     /*
1559                 QPainter painter(&canvas->maps.model);
1560                 painter.setRenderHint(QPainter::Antialiasing);
1561                 FOR(i, testTrajectories.size())
1562                 {
1563                     vector<fvec> &result = testTrajectories[i];
1564                     fvec oldPt = result[0];
1565                     int count = result.size();
1566                     FOR(j, count-1)
1567                     {
1568                         fvec pt = result[j+1];
1569                         painter.setPen(QPen(Qt::green, 2));
1570                         painter.drawLine(canvas->toCanvasCoords(pt), canvas->toCanvasCoords(oldPt));
1571                         oldPt = pt;
1572                     }
1573                     painter.setBrush(Qt::NoBrush);
1574                     painter.setPen(Qt::green);
1575                     painter.drawEllipse(canvas->toCanvasCoords(result[0]), 5, 5);
1576                     painter.setPen(Qt::red);
1577                     painter.drawEllipse(canvas->toCanvasCoords(result[count-1]), 5, 5);
1578                 }
1579                 */
1580                 }
1581                 else
1582                 {
1583                     //pair<fvec,fvec> bounds = canvas->data->GetBounds();
1584                     //Expose::DrawTrajectories(canvas->maps.model, testTrajectories, vector<QColor>(), canvas->canvasType-1, 1, bounds);
1585                 }
1586             }
1587
1588             // the first index is "none", so we subtract 1
1589             int avoidIndex = optionsDynamic->obstacleCombo->currentIndex()-1;
1590             if(avoidIndex >=0 && avoidIndex < avoiders.size() && avoiders[avoidIndex])
1591             {
1592                 DEL(dynamical->avoid);
1593                 dynamical->avoid = avoiders[avoidIndex]->GetObstacleAvoidance();
1594             }
1595             UpdateInfo();
1596             if(dynamicals[tabUsedForTraining]->UsesDrawTimer())
1597             {
1598                 drawTimer->bColorMap = bColorMap;
1599                 drawTimer->start(QThread::NormalPriority);
1600             }
1601         }
1602     }
1603     if(!canvas->canvasType && projector)
1604     {
1605         if(glw->isVisible())
1606         {
1607             glw->clearLists();
1608             if(canvas->canvasType == 1)
1609             {
1610                 projectors[tabUsedForTraining]->DrawGL(canvas, glw, projector);
1611                 if(canvas->data->GetDimCount() == 3) Draw3DProjector(glw, projector);
1612             }
1613         }
1614         else projectors[tabUsedForTraining]->Draw(canvas, projector);
1615     }
1616     UpdateInfo();
1617 }
1618
1619 void MLDemos::DrawClassifiedSamples(Canvas *canvas, Classifier *classifier, std::vector<Classifier *> classifierMulti)
1620 {
1621     if(!canvas || !classifier) return;
1622     int w = canvas->width(), h = canvas->height();
1623     canvas->maps.model = QPixmap(w,h);
1624     QBitmap bitmap(w,h);
1625     bitmap.clear();
1626     canvas->maps.model.setMask(bitmap);
1627     canvas->maps.model.fill(Qt::transparent);
1628     QPainter painter(&canvas->maps.model);
1629
1630     // we draw the samples
1631     painter.setRenderHint(QPainter::Antialiasing, true);
1632     FOR(i, canvas->data->GetCount())
1633     {
1634         fvec sample = canvas->data->GetSample(i);
1635         int label = canvas->data->GetLabel(i);
1636         QPointF point = canvas->toCanvasCoords(canvas->data->GetSample(i));
1637         fvec res;
1638         if(classifier->IsMultiClass()) res = classifier->TestMulti(sample);
1639         else if(classifierMulti.size())
1640         {
1641             FOR(c, classifierMulti.size())
1642             {
1643                 res.push_back(classifierMulti[c]->Test(sample));
1644             }
1645         }
1646         else res.push_back(classifier->Test(sample));
1647         if(res.size()==1)
1648         {
1649             int posClass = 1;
1650             float response = res[0];
1651             if(response > 0)
1652             {
1653                 if(classifier->classMap[label] == posClass) Canvas::drawSample(painter, point, 9, 1);
1654                 else Canvas::drawCross(painter, point, 6, 2);
1655             }
1656             else
1657             {
1658                 if(classifier->classMap[label] != posClass) Canvas::drawSample(painter, point, 9, 0);
1659                 else Canvas::drawCross(painter, point, 6, 0);
1660             }
1661         }
1662         else
1663         {
1664             int max = 0;
1665             for(int i=1; i<res.size(); i++) if(res[max] < res[i]) max = i;
1666             int resp = classifier->inverseMap[max];
1667             if(label == resp) Canvas::drawSample(painter, point, 9, label);
1668             else Canvas::drawCross(painter, point, 6, label);
1669         }
1670     }
1671
1672 }