FIXED: Generator saving/loading of parameters, display of parameters, noise in regres...
[mldemos:mldemos.git] / MLDemos / mldemos.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 <QDebug>
22 #include <QtGui>
23 #include <fstream>
24 #include <QPixmap>
25 #include <QUrl>
26 #include <QBitmap>
27 #include <QSettings>
28 #include <QFileDialog>
29 #include "basicMath.h"
30 #include "drawSVG.h"
31 #include <iostream>
32 #include <sstream>
33 #include "optimization_test_functions.h"
34
35
36 MLDemos::MLDemos(QString filename, QWidget *parent, Qt::WFlags flags)
37     : QMainWindow(parent, flags),
38       canvas(0),
39       expose(0),
40       classifier(0),
41       regressor(0),
42       dynamical(0),
43       clusterer(0),
44       maximizer(0),
45       projector(0),
46       bIsRocNew(true),
47       bIsCrossNew(true),
48       compareDisplay(0),
49       compare(0),
50       trajectory(ipair(-1,-1)),
51       bNewObstacle(false),
52       tabUsedForTraining(0)
53 {
54     QApplication::setWindowIcon(QIcon(":/MLDemos/logo.png"));
55     ui.setupUi(this);
56     setAcceptDrops(true);
57
58     connect(ui.actionExit, SIGNAL(triggered()), qApp, SLOT(quit()));
59     connect(ui.actionAbout, SIGNAL(triggered()), this, SLOT(ShowAbout()));
60     connect(ui.actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
61     connect(ui.actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
62     connect(ui.actionShift_Dimensions, SIGNAL(triggered()), this, SLOT(ShiftDimensions()));
63     connect(ui.actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
64     connect(ui.actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
65     connect(ui.actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
66     connect(ui.actionImportData, SIGNAL(triggered()), this, SLOT(ImportData()));
67     connect(ui.actionExportOutput, SIGNAL(triggered()), this, SLOT(ExportOutput()));
68     connect(ui.actionExportAnimation, SIGNAL(triggered()), this, SLOT(ExportAnimation()));
69     connect(ui.actionExport_SVG, SIGNAL(triggered()), this, SLOT(ExportSVG()));
70     ui.actionImportData->setShortcut(QKeySequence(tr("Ctrl+I")));
71
72     initDialogs();
73     initToolBars();
74     initPlugins();
75     LoadLayoutOptions();
76     SetTextFontSize();
77     ShowToolbar();
78     this->show();
79
80     DisplayOptionChanged();
81     UpdateInfo();
82     FitToData();
83     AlgoChanged();
84     if(!classifiers.size()) algorithmOptions->tabWidget->setTabEnabled(0,false);
85     if(!clusterers.size()) algorithmOptions->tabWidget->setTabEnabled(1,false);
86     if(!regressors.size()) algorithmOptions->tabWidget->setTabEnabled(2,false);
87     if(!projectors.size()) algorithmOptions->tabWidget->setTabEnabled(3,false);
88     if(!dynamicals.size()) algorithmOptions->tabWidget->setTabEnabled(4,false);
89     if(!maximizers.size()) algorithmOptions->tabWidget->setTabEnabled(5,false);
90
91     algorithmWidget->setFixedSize(636,220);
92     canvas->repaint();
93
94     canvas->ResizeEvent();
95     CanvasMoveEvent();
96     CanvasTypeChanged();
97     CanvasOptionsChanged();
98     ResetPositiveClass();
99     ClusterChanged();
100     drawTime.start();
101     if(filename != "") Load(filename);
102 }
103
104 void MLDemos::initToolBars()
105 {
106     actionNew = new QAction(QIcon(":/MLDemos/icons/new.png"), tr("&New"), this);
107     actionNew->setShortcut(QKeySequence(tr("Ctrl+N")));
108     actionNew->setStatusTip(tr("Clear Everything"));
109
110     actionSave = new QAction(QIcon(":/MLDemos/icons/save.png"), tr("&Save"), this);
111     actionSave->setShortcut(QKeySequence(tr("Ctrl+S")));
112     actionSave->setStatusTip(tr("Save Data"));
113
114     actionLoad = new QAction(QIcon(":/MLDemos/icons/load.png"), tr("&Load"), this);
115     actionLoad->setShortcut(QKeySequence(tr("Ctrl+L")));
116     actionLoad->setStatusTip(tr("Load Data"));
117
118     actionAlgorithms = new QAction(QIcon(":/MLDemos/icons/algorithms.png"), tr("&Algorithms"), this);
119     actionAlgorithms->setShortcut(QKeySequence(tr("C")));
120     actionAlgorithms->setStatusTip(tr("Algorithm Options"));
121     actionAlgorithms->setCheckable(true);
122
123     actionCompare = new QAction(QIcon(":/MLDemos/icons/compare.png"), tr("&Compare"), this);
124     actionCompare->setShortcut(QKeySequence(tr("M")));
125     actionCompare->setStatusTip(tr("Compare Algorithms"));
126     actionCompare->setCheckable(true);
127
128     actionDrawSamples = new QAction(QIcon(":/MLDemos/icons/draw.png"), tr("&Drawing"), this);
129     actionDrawSamples->setShortcut(QKeySequence(tr("W")));
130     actionDrawSamples->setStatusTip(tr("Show Sample Drawing Options"));
131     actionDrawSamples->setCheckable(true);
132
133     actionAddData = new QAction(QIcon(":/MLDemos/icons/adddata.png"), tr("Add Data"), this);
134     actionAddData->setShortcut(QKeySequence(tr("A")));
135     actionAddData->setStatusTip(tr("Add new data"));
136     actionAddData->setCheckable(true);
137
138     actionClearModel = new QAction(QIcon(":/MLDemos/icons/clearmodel.png"), tr("Clear Model"), this);
139     actionClearModel->setShortcut(QKeySequence(tr("Shift+X")));
140     actionClearModel->setStatusTip(tr("Clear current model"));
141
142     actionClearData = new QAction(QIcon(":/MLDemos/icons/cleardata.png"), tr("Clear Data"), this);
143     actionClearData->setShortcut(QKeySequence(tr("X")));
144     actionClearData->setStatusTip(tr("Clear all data"));
145
146     actionScreenshot = new QAction(QIcon(":/MLDemos/icons/screenshot.png"), tr("Save Screenshot"), this);
147     actionScreenshot->setShortcut(QKeySequence(tr("Alt+S")));
148     actionScreenshot->setStatusTip(tr("Save the current image to disk"));
149
150     actionDisplayOptions = new QAction(QIcon(":/MLDemos/icons/display.png"), tr("Display &Options"), this);
151     actionDisplayOptions->setShortcut(QKeySequence(tr("O")));
152     actionDisplayOptions->setStatusTip(tr("Show Display Options"));
153     actionDisplayOptions->setCheckable(true);
154
155     actionShowStats = new QAction(QIcon(":/MLDemos/icons/stats.png"), tr("Info/Statistics"), this);
156     actionShowStats->setShortcut(QKeySequence(tr("I")));
157     actionShowStats->setStatusTip(tr("Display Algorithm Information and Data Statistics"));
158     actionShowStats->setCheckable(true);
159
160     connect(actionAlgorithms, SIGNAL(triggered()), this, SLOT(ShowAlgorithmOptions()));
161     connect(actionCompare, SIGNAL(triggered()), this, SLOT(ShowOptionCompare()));
162     connect(actionDrawSamples, SIGNAL(triggered()), this, SLOT(ShowSampleDrawing()));
163     connect(actionDisplayOptions, SIGNAL(triggered()), this, SLOT(ShowOptionDisplay()));
164     connect(actionAddData, SIGNAL(triggered()), this, SLOT(ShowAddData()));
165     connect(generator, SIGNAL(finished()), this, SLOT(HideAddData()));
166     connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
167     connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
168     connect(actionScreenshot, SIGNAL(triggered()), this, SLOT(Screenshot()));
169     connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
170     connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
171     connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
172     connect(actionShowStats, SIGNAL(triggered()), this, SLOT(ShowStatsDialog()));
173
174     /*
175  connect(actionClearData, SIGNAL(triggered()), this, SLOT(ClearData()));
176  connect(actionClearModel, SIGNAL(triggered()), this, SLOT(Clear()));
177  connect(actionNew, SIGNAL(triggered()), this, SLOT(ClearData()));
178  connect(actionSave, SIGNAL(triggered()), this, SLOT(SaveData()));
179  connect(actionLoad, SIGNAL(triggered()), this, SLOT(LoadData()));
180  */
181
182     toolBar = addToolBar("Tools");
183     toolBar->setObjectName("MainToolBar");
184     toolBar->setMovable(false);
185     toolBar->setFloatable(false);
186     toolBar->setIconSize(QSize(32,32));
187     toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
188
189     toolBar->addAction(actionNew);
190     toolBar->addAction(actionLoad);
191     toolBar->addAction(actionSave);
192     toolBar->addSeparator();
193     toolBar->addAction(actionAlgorithms);
194     toolBar->addAction(actionCompare);
195     toolBar->addSeparator();
196     toolBar->addAction(actionAddData);
197     toolBar->addAction(actionClearModel);
198     toolBar->addAction(actionClearData);
199     toolBar->addSeparator();
200     toolBar->addAction(actionDrawSamples);
201     toolBar->addSeparator();
202     toolBar->addAction(actionScreenshot);
203     toolBar->addAction(actionDisplayOptions);
204     toolBar->addAction(actionShowStats);
205     toolBar->setVisible(true);
206
207     connect(toolBar, SIGNAL(topLevelChanged(bool)), this, SLOT(ShowToolbar()));
208     connect(ui.actionShow_Toolbar, SIGNAL(triggered()), this, SLOT(ShowToolbar()));
209     connect(ui.actionSmall_Icons, SIGNAL(triggered()), this, SLOT(ShowToolbar()));
210     connect(ui.canvasTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(CanvasTypeChanged()));
211     connect(ui.canvasZoomSlider, SIGNAL(valueChanged(int)), this, SLOT(CanvasOptionsChanged()));
212     connect(ui.canvasX1Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionChanged()));
213     connect(ui.canvasX2Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionChanged()));
214     connect(ui.canvasX3Spin, SIGNAL(valueChanged(int)), this, SLOT(DisplayOptionChanged()));
215
216     QSize iconSize(24,24);
217     drawToolbar->singleButton->setIcon(QIcon(":/MLDemos/icons/brush.png"));
218     drawToolbar->singleButton->setIconSize(iconSize);
219     drawToolbar->singleButton->setText("");
220     drawToolbar->sprayButton->setIcon(QIcon(":/MLDemos/icons/airbrush.png"));
221     drawToolbar->sprayButton->setIconSize(iconSize);
222     drawToolbar->sprayButton->setText("");
223     drawToolbar->eraseButton->setIcon(QIcon(":/MLDemos/icons/erase.png"));
224     drawToolbar->eraseButton->setIconSize(iconSize);
225     drawToolbar->eraseButton->setText("");
226     drawToolbar->trajectoryButton->setIcon(QIcon(":/MLDemos/icons/trajectory.png"));
227     drawToolbar->trajectoryButton->setIconSize(iconSize);
228     drawToolbar->trajectoryButton->setText("");
229     drawToolbar->lineButton->setIcon(QIcon(":/MLDemos/icons/line.png"));
230     drawToolbar->lineButton->setIconSize(iconSize);
231     drawToolbar->lineButton->setText("");
232     drawToolbar->ellipseButton->setIcon(QIcon(":/MLDemos/icons/ellipse.png"));
233     drawToolbar->ellipseButton->setIconSize(iconSize);
234     drawToolbar->ellipseButton->setText("");
235     drawToolbar->paintButton->setIcon(QIcon(":/MLDemos/icons/bigbrush.png"));
236     drawToolbar->paintButton->setIconSize(iconSize);
237     drawToolbar->paintButton->setText("");
238     drawToolbar->obstacleButton->setIcon(QIcon(":/MLDemos/icons/obstacle.png"));
239     drawToolbar->obstacleButton->setIconSize(iconSize);
240     drawToolbar->obstacleButton->setText("");
241 }
242
243 void MLDemos::initDialogs()
244 {
245     drawToolbar = new Ui::DrawingToolbar();
246     drawToolbarContext1 = new Ui::DrawingToolbarContext1();
247     drawToolbarContext2 = new Ui::DrawingToolbarContext2();
248     drawToolbarContext3 = new Ui::DrawingToolbarContext3();
249     drawToolbarContext4 = new Ui::DrawingToolbarContext4();
250
251     drawToolbar->setupUi(drawToolbarWidget = new QWidget());
252     drawToolbarContext1->setupUi(drawContext1Widget = new QWidget());
253     drawToolbarContext2->setupUi(drawContext2Widget = new QWidget());
254     drawToolbarContext3->setupUi(drawContext3Widget = new QWidget());
255     drawToolbarContext4->setupUi(drawContext4Widget = new QWidget());
256
257     connect(qApp, SIGNAL(focusChanged(QWidget *,QWidget *)),this,SLOT(FocusChanged(QWidget *,QWidget *)));
258
259     drawToolbar->sprayButton->setContextMenuPolicy(Qt::CustomContextMenu);
260     drawToolbar->ellipseButton->setContextMenuPolicy(Qt::CustomContextMenu);
261     drawToolbar->lineButton->setContextMenuPolicy(Qt::CustomContextMenu);
262     drawToolbar->eraseButton->setContextMenuPolicy(Qt::CustomContextMenu);
263     drawToolbar->obstacleButton->setContextMenuPolicy(Qt::CustomContextMenu);
264     drawToolbar->paintButton->setContextMenuPolicy(Qt::CustomContextMenu);
265     connect(drawToolbar->sprayButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuSpray(const QPoint &)));
266     connect(drawToolbar->ellipseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuEllipse(const QPoint &)));
267     connect(drawToolbar->lineButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuLine(const QPoint &)));
268     connect(drawToolbar->eraseButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuErase(const QPoint &)));
269     connect(drawToolbar->obstacleButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuObstacle(const QPoint &)));
270     connect(drawToolbar->paintButton, SIGNAL(customContextMenuRequested( const QPoint& )), this, SLOT(ShowContextMenuReward(const QPoint &)));
271
272     displayOptions = new Ui::viewOptionDialog();
273     aboutPanel = new Ui::aboutDialog();
274     showStats = new Ui::statisticsDialog();
275     manualSelection = new Ui::ManualSelection();
276     inputDimensions = new Ui::InputDimensions();
277
278     displayOptions->setupUi(displayDialog = new QDialog());
279     aboutPanel->setupUi(about = new QDialog());
280     showStats->setupUi(statsDialog = new QDialog());
281     manualSelection->setupUi(manualSelectDialog = new QDialog());
282     inputDimensions->setupUi(inputDimensionsDialog = new QDialog());
283     rocWidget = new QNamedWindow("ROC Curve", false, showStats->rocWidget);
284     infoWidget = new QNamedWindow("Info", false, showStats->informationWidget);
285
286
287     connect(showStats->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(StatsChanged()));
288     connect(rocWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged()));
289     connect(infoWidget, SIGNAL(ResizeEvent(QResizeEvent *)), this, SLOT(StatsChanged()));
290     connect(manualSelection->sampleList, SIGNAL(itemSelectionChanged()), this, SLOT(ManualSelectionChanged()));
291     connect(manualSelection->clearSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionClear()));
292     connect(manualSelection->invertSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionInvert()));
293     connect(manualSelection->removeSampleButton, SIGNAL(clicked()), this, SLOT(ManualSelectionRemove()));
294     connect(manualSelection->randomizeSelectionButton, SIGNAL(clicked()), this, SLOT(ManualSelectionRandom()));
295     connect(inputDimensions->dimList, SIGNAL(itemSelectionChanged()), this, SLOT(InputDimensionsChanged()));
296     connect(inputDimensions->clearSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsClear()));
297     connect(inputDimensions->invertSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsInvert()));
298     connect(inputDimensions->randomizeSelectionButton, SIGNAL(clicked()), this, SLOT(InputDimensionsRandom()));
299
300     connect(drawToolbar->singleButton, SIGNAL(clicked()), this, SLOT(DrawSingle()));
301     connect(drawToolbar->sprayButton, SIGNAL(clicked()), this, SLOT(DrawSpray()));
302     connect(drawToolbar->lineButton, SIGNAL(clicked()), this, SLOT(DrawLine()));
303     connect(drawToolbar->ellipseButton, SIGNAL(clicked()), this, SLOT(DrawEllipse()));
304     connect(drawToolbar->eraseButton, SIGNAL(clicked()), this, SLOT(DrawErase()));
305     connect(drawToolbar->trajectoryButton, SIGNAL(clicked()), this, SLOT(DrawTrajectory()));
306     connect(drawToolbar->obstacleButton, SIGNAL(clicked()), this, SLOT(DrawObstacle()));
307     connect(drawToolbar->paintButton, SIGNAL(clicked()), this, SLOT(DrawPaint()));
308
309     connect(displayOptions->clipboardButton, SIGNAL(clicked()), this, SLOT(ToClipboard()));
310     connect(displayOptions->mapCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
311     connect(displayOptions->modelCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
312     connect(displayOptions->infoCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
313     connect(displayOptions->samplesCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
314     connect(displayOptions->gridCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
315     connect(displayOptions->spinZoom, SIGNAL(valueChanged(double)), this, SLOT(DisplayOptionChanged()));
316     connect(displayOptions->zoomFitButton, SIGNAL(clicked()), this, SLOT(FitToData()));
317     connect(displayOptions->legendCheck, SIGNAL(clicked()), this, SLOT(DisplayOptionChanged()));
318
319     algorithmOptions = new Ui::algorithmOptions();
320     optionsClassify = new Ui::optionsClassifyWidget();
321     optionsCluster = new Ui::optionsClusterWidget();
322     optionsRegress = new Ui::optionsRegressWidget();
323     optionsDynamic = new Ui::optionsDynamicWidget();
324     optionsMaximize = new Ui::optionsMaximizeWidget();
325     optionsProject = new Ui::optionsProjectWidget();
326     optionsCompare = new Ui::optionsCompare();
327
328     algorithmWidget = new QWidget();
329     algorithmOptions->setupUi(algorithmWidget);
330
331     algorithmWidget->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac
332     //algorithmWidget->setWindowFlags(Qt::WindowStaysOnTopHint);
333     displayDialog->setWindowFlags(Qt::Tool); // disappears when unfocused on the mac
334     //drawToolbarWidget->setWindowFlags(Qt::Tool);
335     drawToolbarWidget->setWindowFlags(Qt::CustomizeWindowHint | Qt::Tool | Qt::WindowTitleHint);
336     drawContext1Widget->setWindowFlags(Qt::FramelessWindowHint);
337     drawContext2Widget->setWindowFlags(Qt::FramelessWindowHint);
338     drawContext3Widget->setWindowFlags(Qt::FramelessWindowHint);
339     drawContext4Widget->setWindowFlags(Qt::FramelessWindowHint);
340     drawToolbarWidget->setFixedSize(drawToolbarWidget->size());
341
342     classifyWidget = new QWidget(algorithmOptions->tabClass);
343     clusterWidget = new QWidget(algorithmOptions->tabClust);
344     regressWidget = new QWidget(algorithmOptions->tabRegr);
345     dynamicWidget = new QWidget(algorithmOptions->tabDyn);
346     maximizeWidget = new QWidget(algorithmOptions->tabMax);
347     projectWidget = new QWidget(algorithmOptions->tabProj);
348     optionsClassify->setupUi(classifyWidget);
349     optionsCluster->setupUi(clusterWidget);
350     optionsRegress->setupUi(regressWidget);
351     optionsDynamic->setupUi(dynamicWidget);
352     optionsMaximize->setupUi(maximizeWidget);
353     optionsProject->setupUi(projectWidget);
354     compareWidget = new QWidget();
355     optionsCompare->setupUi(compareWidget);
356     optionsDynamic->targetButton->setAcceptDrops(true);
357
358     connect(displayDialog, SIGNAL(rejected()), this, SLOT(HideOptionDisplay()));
359     connect(statsDialog, SIGNAL(rejected()), this, SLOT(HideStatsDialog()));
360     //connect(manualSelectDialog, SIGNAL(rejected()), this, SLOT(HideManualSelectionDialog()));
361
362     connect(optionsClassify->classifyButton, SIGNAL(clicked()), this, SLOT(Classify()));
363     connect(optionsClassify->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
364     connect(optionsClassify->rocButton, SIGNAL(clicked()), this, SLOT(ShowRoc()));
365     connect(optionsClassify->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
366     connect(optionsClassify->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
367     connect(optionsClassify->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions()));
368
369     connect(optionsRegress->regressionButton, SIGNAL(clicked()), this, SLOT(Regression()));
370     connect(optionsRegress->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
371     //connect(optionsRegress->svmTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
372     connect(optionsRegress->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
373     connect(optionsRegress->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
374     connect(optionsRegress->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions()));
375
376     connect(optionsCluster->clusterButton, SIGNAL(clicked()), this, SLOT(Cluster()));
377     connect(optionsCluster->iterationButton, SIGNAL(clicked()), this, SLOT(ClusterIterate()));
378     connect(optionsCluster->optimizeButton, SIGNAL(clicked()), this, SLOT(ClusterOptimize()));
379     connect(optionsCluster->testButton, SIGNAL(clicked()), this, SLOT(ClusterTest()));
380     connect(optionsCluster->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
381     connect(optionsCluster->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
382     connect(optionsCluster->optimizeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ClusterChanged()));
383
384     connect(optionsDynamic->regressionButton, SIGNAL(clicked()), this, SLOT(Dynamize()));
385     connect(optionsDynamic->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
386     connect(optionsDynamic->centerCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
387     connect(optionsDynamic->resampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
388     connect(optionsDynamic->resampleSpin, SIGNAL(valueChanged(int)), this, SLOT(ChangeActiveOptions()));
389     connect(optionsDynamic->loadButton, SIGNAL(clicked()), this, SLOT(LoadDynamical()));
390     connect(optionsDynamic->saveButton, SIGNAL(clicked()), this, SLOT(SaveDynamical()));
391     connect(optionsDynamic->dtSpin, SIGNAL(valueChanged(double)), this, SLOT(ChangeActiveOptions()));
392     connect(optionsDynamic->obstacleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(AvoidOptionChanged()));
393     connect(optionsDynamic->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
394     connect(optionsDynamic->colorCheck, SIGNAL(clicked()), this, SLOT(ColorMapChanged()));
395     connect(optionsDynamic->resampleCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(ChangeActiveOptions()));
396     connect(optionsDynamic->targetButton, SIGNAL(pressed()), this, SLOT(TargetButton()));
397     connect(optionsDynamic->clearTargetButton, SIGNAL(clicked()), this, SLOT(ClearTargets()));
398
399     connect(optionsMaximize->maximizeButton, SIGNAL(clicked()), this, SLOT(Maximize()));
400     connect(optionsMaximize->pauseButton, SIGNAL(clicked()), this, SLOT(MaximizeContinue()));
401     connect(optionsMaximize->clearButton, SIGNAL(clicked()), this, SLOT(Clear()));
402     connect(optionsMaximize->targetButton, SIGNAL(pressed()), this, SLOT(TargetButton()));
403     connect(optionsMaximize->gaussianButton, SIGNAL(pressed()), this, SLOT(GaussianButton()));
404     connect(optionsMaximize->gradientButton, SIGNAL(pressed()), this, SLOT(GradientButton()));
405     connect(optionsMaximize->benchmarkButton, SIGNAL(clicked()), this, SLOT(BenchmarkButton()));
406     connect(optionsMaximize->compareButton, SIGNAL(clicked()), this, SLOT(CompareAdd()));
407
408     connect(optionsProject->projectButton, SIGNAL(clicked()), this, SLOT(Project()));
409     connect(optionsProject->revertButton, SIGNAL(clicked()), this, SLOT(ProjectRevert()));
410     connect(optionsProject->reprojectButton, SIGNAL(clicked()), this, SLOT(ProjectReproject()));
411     connect(optionsProject->manualTrainButton, SIGNAL(clicked()), this, SLOT(ManualSelection()));
412
413     connect(optionsCompare->compareButton, SIGNAL(clicked()), this, SLOT(Compare()));
414     connect(optionsCompare->screenshotButton, SIGNAL(clicked()), this, SLOT(CompareScreenshot()));
415     connect(optionsCompare->clearButton, SIGNAL(clicked()), this, SLOT(CompareClear()));
416     connect(optionsCompare->removeButton, SIGNAL(clicked()), this, SLOT(CompareRemove()));
417     connect(optionsCompare->inputDimButton, SIGNAL(clicked()), this, SLOT(InputDimensions()));
418
419     connect(optionsRegress->outputDimCombo, SIGNAL(currentIndexChanged(int)), optionsCompare->outputDimCombo, SLOT(setCurrentIndex(int)));
420     connect(optionsCompare->outputDimCombo, SIGNAL(currentIndexChanged(int)), optionsRegress->outputDimCombo, SLOT(setCurrentIndex(int)));
421
422     optionsClassify->tabWidget->clear();
423     optionsCluster->tabWidget->clear();
424     optionsRegress->tabWidget->clear();
425     optionsDynamic->tabWidget->clear();
426     optionsMaximize->tabWidget->clear();
427     optionsProject->tabWidget->clear();
428     optionsClassify->tabWidget->setUsesScrollButtons(true);
429     optionsCluster->tabWidget->setUsesScrollButtons(true);
430     optionsRegress->tabWidget->setUsesScrollButtons(true);
431     optionsDynamic->tabWidget->setUsesScrollButtons(true);
432     optionsMaximize->tabWidget->setUsesScrollButtons(true);
433     optionsProject->tabWidget->setUsesScrollButtons(true);
434
435     QHBoxLayout *layout = new QHBoxLayout(optionsCompare->resultWidget);
436     compare = new CompareAlgorithms(optionsCompare->resultWidget);
437
438     connect(algorithmOptions->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
439     connect(optionsClassify->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
440     connect(optionsCluster->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
441     connect(optionsRegress->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
442     connect(optionsDynamic->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
443     connect(optionsMaximize->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
444     connect(optionsProject->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(AlgoChanged()));
445
446     //canvas = new Canvas(ui.centralWidget);
447     canvas = new Canvas(ui.canvasWidget);
448     connect(canvas, SIGNAL(Drawing(fvec,int)), this, SLOT(Drawing(fvec,int)));
449     connect(canvas, SIGNAL(DrawCrosshair()), this, SLOT(DrawCrosshair()));
450     connect(canvas, SIGNAL(Navigation(fvec)), this, SLOT(Navigation(fvec)));
451     connect(canvas, SIGNAL(Released()), this, SLOT(DrawingStopped()));
452     connect(canvas, SIGNAL(CanvasMoveEvent()), this, SLOT(CanvasMoveEvent()));
453     //connect(canvas, SIGNAL(ZoomChanged()), this, SLOT(ZoomChanged()));
454     drawTimer = new DrawTimer(canvas, &mutex);
455     drawTimer->classifier = &classifier;
456     drawTimer->regressor = &regressor;
457     drawTimer->dynamical = &dynamical;
458     drawTimer->clusterer = &clusterer;
459     drawTimer->maximizer = &maximizer;
460     connect(drawTimer, SIGNAL(MapReady(QImage)), canvas, SLOT(SetConfidenceMap(QImage)));
461     connect(drawTimer, SIGNAL(ModelReady(QImage)), canvas, SLOT(SetModelImage(QImage)));
462     connect(drawTimer, SIGNAL(CurveReady()), this, SLOT(SetROCInfo()));
463     connect(drawTimer, SIGNAL(AnimationReady(QImage)), canvas, SLOT(SetAnimationImage(QImage)));
464
465     expose = new Expose(canvas);
466     import = new DataImporter();
467     generator = new DataGenerator(canvas, &mutex);
468     connect(import, import->SetDataSignal(), this, SLOT(SetData(std::vector<fvec>, ivec, std::vector<ipair>, bool)));
469     connect(import, import->SetTimeseriesSignal(), this, SLOT(SetTimeseries(std::vector<TimeSerie>)));
470     connect(import, SIGNAL(SetDimensionNames(QStringList)), this, SLOT(SetDimensionNames(QStringList)));
471     connect(import, SIGNAL(SetClassNames(std::map<int,QString>)), this, SLOT(SetClassNames(std::map<int,QString>)));
472 }
473
474 void MLDemos::initPlugins()
475 {
476     qDebug() << "Importing plugins";
477     QDir pluginsDir = QDir(qApp->applicationDirPath());
478     QStringList pluginFileNames;
479     QDir alternativeDir = pluginsDir;
480
481 #if defined(Q_OS_WIN)
482     if (pluginsDir.dirName().toLower() == "debug" || pluginsDir.dirName().toLower() == "release") pluginsDir.cdUp();
483 #elif defined(Q_OS_MAC)
484     if (pluginsDir.dirName() == "MacOS") {
485         if(!pluginsDir.cd("plugins"))
486         {
487             qDebug() << "looking for alternative directory";
488             pluginsDir.cdUp();
489             pluginsDir.cdUp();
490             alternativeDir = pluginsDir;
491             alternativeDir.cd("plugins");
492         }
493         pluginsDir.cdUp();
494     }
495 #endif
496     bool bFoundPlugins = false;
497 #if defined(DEBUG)
498     qDebug() << "looking for debug plugins";
499     bFoundPlugins = pluginsDir.cd("pluginsDebug");
500 #else
501     qDebug() << "looking for release plugins";
502     bFoundPlugins = pluginsDir.cd("plugins");
503 #endif
504     if(!bFoundPlugins)
505     {
506         qDebug() << "plugins not found on: " << pluginsDir.absolutePath();
507         qDebug() << "using alternative directory: " << alternativeDir.absolutePath();
508         pluginsDir = alternativeDir;
509     }
510     foreach (QString fileName, pluginsDir.entryList(QDir::Files))
511     {
512         QPluginLoader loader(pluginsDir.absoluteFilePath(fileName));
513         QObject *plugin = loader.instance();
514         if (plugin)
515         {
516             qDebug() << "loading " << fileName;
517             // check type of plugin
518             CollectionInterface *iCollection = qobject_cast<CollectionInterface *>(plugin);
519             if(iCollection)
520             {
521                 std::vector<ClassifierInterface*> classifierList = iCollection->GetClassifiers();
522                 std::vector<ClustererInterface*> clustererList = iCollection->GetClusterers();
523                 std::vector<RegressorInterface*> regressorList = iCollection->GetRegressors();
524                 std::vector<DynamicalInterface*> dynamicalList = iCollection->GetDynamicals();
525                 std::vector<MaximizeInterface*> maximizerList = iCollection->GetMaximizers();
526                 std::vector<ProjectorInterface*> projectorList = iCollection->GetProjectors();
527                 FOR(i, classifierList.size()) AddPlugin(classifierList[i], SLOT(ChangeActiveOptions));
528                 FOR(i, clustererList.size()) AddPlugin(clustererList[i], SLOT(ChangeActiveOptions));
529                 FOR(i, regressorList.size()) AddPlugin(regressorList[i], SLOT(ChangeActiveOptions));
530                 FOR(i, dynamicalList.size()) AddPlugin(dynamicalList[i], SLOT(ChangeActiveOptions));
531                 FOR(i, maximizerList.size()) AddPlugin(maximizerList[i], SLOT(ChangeActiveOptions));
532                 FOR(i, projectorList.size()) AddPlugin(projectorList[i], SLOT(ChangeActiveOptions));
533                 continue;
534             }
535             ClassifierInterface *iClassifier = qobject_cast<ClassifierInterface *>(plugin);
536             if (iClassifier)
537             {
538                 AddPlugin(iClassifier, SLOT(ChangeActiveOptions()));
539                 continue;
540             }
541             ClustererInterface *iClusterer = qobject_cast<ClustererInterface *>(plugin);
542             if (iClusterer)
543             {
544                 AddPlugin(iClusterer, SLOT(ChangeActiveOptions()));
545                 continue;
546             }
547             RegressorInterface *iRegressor = qobject_cast<RegressorInterface *>(plugin);
548             if (iRegressor)
549             {
550                 AddPlugin(iRegressor, SLOT(ChangeActiveOptions()));
551                 continue;
552             }
553             DynamicalInterface *iDynamical = qobject_cast<DynamicalInterface *>(plugin);
554             if (iDynamical)
555             {
556                 AddPlugin(iDynamical, SLOT(ChangeActiveOptions()));
557                 continue;
558             }
559             MaximizeInterface *iMaximize = qobject_cast<MaximizeInterface *>(plugin);
560             if (iMaximize)
561             {
562                 AddPlugin(iMaximize, SLOT(ChangeActiveOptions()));
563                 continue;
564             }
565             ProjectorInterface *iProject = qobject_cast<ProjectorInterface *>(plugin);
566             if (iProject)
567             {
568                 AddPlugin(iProject, SLOT(ChangeActiveOptions()));
569                 continue;
570             }
571             InputOutputInterface *iIO = qobject_cast<InputOutputInterface *>(plugin);
572             if (iIO)
573             {
574                 AddPlugin(iIO);
575                 continue;
576             }
577             AvoidanceInterface *iAvoid = qobject_cast<AvoidanceInterface *>(plugin);
578             if (iAvoid)
579             {
580                 AddPlugin(iAvoid, SLOT(ChangeActiveOptions()));
581                 continue;
582             }
583         }
584         else
585             qDebug() << loader.errorString();
586     }
587 }
588
589 void MLDemos::SetTextFontSize()
590 {
591 #if defined(Q_OS_MAC)
592     return; // default fontsizes are for mac already ;)
593 #endif
594     QFont font("Lucida Sans Unicode", 7);
595     QList<QWidget*> children = algorithmWidget->findChildren<QWidget*>();
596     FOR(i, children.size())
597     {
598         if(children[i]) children[i]->setFont(font);
599     }
600     optionsMaximize->gaussianButton->setFont(QFont("Lucida Sans Unicode", 18));
601     optionsMaximize->gradientButton->setFont(QFont("Lucida Sans Unicode", 18));
602     optionsMaximize->targetButton->setFont(QFont("Lucida Sans Unicode", 18));
603 }
604
605 void MLDemos::ShowContextMenuSpray(const QPoint &point)
606 {
607     HideContextMenus();
608     QPoint pt = QPoint(30, 0);
609     drawContext1Widget->move(drawToolbar->sprayButton->mapToGlobal(pt));
610     drawContext1Widget->show();
611     drawContext1Widget->setFocus();
612     drawContext1Widget->update();
613     update();
614 }
615 void MLDemos::ShowContextMenuLine(const QPoint &point)
616 {
617     HideContextMenus();
618     QPoint pt = QPoint(30, 0);
619     drawContext2Widget->move(drawToolbar->lineButton->mapToGlobal(pt));
620     drawContext2Widget->show();
621     drawContext2Widget->setFocus();
622     drawContext2Widget->update();
623     update();
624 }
625 void MLDemos::ShowContextMenuEllipse(const QPoint &point)
626 {
627     HideContextMenus();
628     QPoint pt = QPoint(30, 0);
629     drawContext2Widget->move(drawToolbar->ellipseButton->mapToGlobal(pt));
630     drawContext2Widget->show();
631     drawContext2Widget->setFocus();
632     drawContext2Widget->update();
633     update();
634 }
635 void MLDemos::ShowContextMenuErase(const QPoint &point)
636 {
637     HideContextMenus();
638     QPoint pt = QPoint(30, 0);
639     drawContext1Widget->move(drawToolbar->eraseButton->mapToGlobal(pt));
640     drawContext1Widget->show();
641     drawContext1Widget->setFocus();
642     drawContext1Widget->update();
643     update();
644 }
645 void MLDemos::ShowContextMenuObstacle(const QPoint &point)
646 {
647     HideContextMenus();
648     QPoint pt = QPoint(30, 0);
649     drawContext3Widget->move(drawToolbar->obstacleButton->mapToGlobal(pt));
650     drawContext3Widget->show();
651     drawContext3Widget->setFocus();
652     drawContext3Widget->update();
653     update();
654 }
655 void MLDemos::ShowContextMenuReward(const QPoint &point)
656 {
657     HideContextMenus();
658     QPoint pt = QPoint(30, 0);
659     drawContext4Widget->move(drawToolbar->paintButton->mapToGlobal(pt));
660     drawContext4Widget->show();
661     drawContext4Widget->setFocus();
662     drawContext4Widget->update();
663     update();
664 }
665
666 bool IsChildOf(QObject *child, QObject *parent)
667 {
668     if(!parent || !child) return false;
669     if(child == parent) return true;
670     QList<QObject*> list = parent->children();
671     if(list.isEmpty()) return false;
672     QList<QObject*>::iterator i;
673     for (i = list.begin(); i<list.end(); ++i)
674     {
675         if(IsChildOf(child, *i)) return true;
676     }
677     return false;
678 }
679
680 void MLDemos::FocusChanged(QWidget *old, QWidget *now)
681 {
682     if(drawContext1Widget->isVisible())
683     {
684         if(!IsChildOf(now, drawContext1Widget)) HideContextMenus();
685     }
686     if(drawContext2Widget->isVisible())
687     {
688         if(!IsChildOf(now, drawContext2Widget)) HideContextMenus();
689     }
690     if(drawContext3Widget->isVisible())
691     {
692         if(!IsChildOf(now, drawContext3Widget)) HideContextMenus();
693     }
694     if(drawContext4Widget->isVisible())
695     {
696         if(!IsChildOf(now, drawContext4Widget)) HideContextMenus();
697     }
698 }
699
700 void MLDemos::HideContextMenus()
701 {
702     drawContext1Widget->hide();
703     drawContext2Widget->hide();
704     drawContext3Widget->hide();
705     drawContext4Widget->hide();
706 }
707
708 void MLDemos::AddPlugin(InputOutputInterface *iIO)
709 {
710     inputoutputs.push_back(iIO);
711     bInputRunning.push_back(false);
712     connect(this, SIGNAL(SendResults(std::vector<fvec>)), iIO->object(), iIO->FetchResultsSlot());
713     connect(iIO->object(), iIO->SetDataSignal(), this, SLOT(SetData(std::vector<fvec>, ivec, std::vector<ipair>, bool)));
714     connect(iIO->object(), iIO->SetTimeseriesSignal(), this, SLOT(SetTimeseries(std::vector<TimeSerie>)));
715     connect(iIO->object(), iIO->QueryClassifierSignal(), this, SLOT(QueryClassifier(std::vector<fvec>)));
716     connect(iIO->object(), iIO->QueryRegressorSignal(), this, SLOT(QueryRegressor(std::vector<fvec>)));
717     connect(iIO->object(), iIO->QueryDynamicalSignal(), this, SLOT(QueryDynamical(std::vector<fvec>)));
718     connect(iIO->object(), iIO->QueryClustererSignal(), this, SLOT(QueryClusterer(std::vector<fvec>)));
719     connect(iIO->object(), iIO->QueryMaximizerSignal(), this, SLOT(QueryMaximizer(std::vector<fvec>)));
720     connect(iIO->object(), iIO->DoneSignal(), this, SLOT(DisactivateIO(QObject *)));
721     QString name = iIO->GetName();
722     QAction *pluginAction = ui.menuInput_Output->addAction(name);
723     pluginAction->setCheckable(true);
724     pluginAction->setChecked(false);
725     connect(pluginAction,SIGNAL(toggled(bool)), this, SLOT(ActivateIO()));
726     QAction *importAction = ui.menuImport->addAction(name);
727     importAction->setCheckable(true);
728     importAction->setChecked(false);
729     connect(importAction,SIGNAL(toggled(bool)), this, SLOT(ActivateImport()));
730 }
731
732 void MLDemos::AddPlugin(ClassifierInterface *iClassifier, const char *method)
733 {
734     if(!iClassifier) return;
735     // we add the interface so we can use it to produce classifiers
736     classifiers.push_back(iClassifier);
737     // we add the classifier parameters to the gui
738     optionsClassify->tabWidget->addTab(iClassifier->GetParameterWidget(), iClassifier->GetName());
739 }
740
741 void MLDemos::AddPlugin(ClustererInterface *iCluster, const char *method)
742 {
743     if(!iCluster) return;
744     clusterers.push_back(iCluster);
745     optionsCluster->tabWidget->addTab(iCluster->GetParameterWidget(), iCluster->GetName());
746 }
747
748 void MLDemos::AddPlugin(RegressorInterface *iRegress, const char *method)
749 {
750     if(!iRegress) return;
751     regressors.push_back(iRegress);
752     optionsRegress->tabWidget->addTab(iRegress->GetParameterWidget(), iRegress->GetName());
753 }
754
755 void MLDemos::AddPlugin(DynamicalInterface *iDynamical, const char *method)
756 {
757     if(!iDynamical) return;
758     dynamicals.push_back(iDynamical);
759     optionsDynamic->tabWidget->addTab(iDynamical->GetParameterWidget(), iDynamical->GetName());
760 }
761
762 void MLDemos::AddPlugin(AvoidanceInterface *iAvoid, const char *method)
763 {
764     if(!iAvoid) return;
765     avoiders.push_back(iAvoid);
766     optionsDynamic->obstacleCombo->addItem(iAvoid->GetName());
767 }
768
769 void MLDemos::AddPlugin(MaximizeInterface *iMaximizer, const char *method)
770 {
771     if(!iMaximizer) return;
772     maximizers.push_back(iMaximizer);
773     optionsMaximize->tabWidget->addTab(iMaximizer->GetParameterWidget(), iMaximizer->GetName());
774 }
775
776 void MLDemos::AddPlugin(ProjectorInterface *iProject, const char *method)
777 {
778     if(!iProject) return;
779     projectors.push_back(iProject);
780     optionsProject->tabWidget->addTab(iProject->GetParameterWidget(), iProject->GetName());
781 }
782
783 MLDemos::~MLDemos()
784 {
785     Clear();
786     FOR(i, inputoutputs.size())
787     {
788         if(inputoutputs[i] && bInputRunning[i]) inputoutputs[i]->Stop();
789     }
790     SaveLayoutOptions();
791     delete optionsClassify;
792     delete optionsRegress;
793     delete optionsCluster;
794     delete optionsDynamic;
795     delete optionsMaximize;
796     delete drawToolbar;
797     delete drawToolbarContext1;
798     delete drawToolbarContext2;
799     delete displayOptions;
800     delete generator;
801     canvas->hide();
802     delete canvas;
803 }
804
805 void MLDemos::closeEvent(QCloseEvent *event)
806 {
807     if (true)
808     {
809         mutex.lock();
810         DEL(regressor);
811         DEL(classifier);
812         mutex.unlock();
813         qApp->quit();
814     } else {
815         event->ignore();
816     }
817 }
818
819 void MLDemos::resizeEvent( QResizeEvent *event )
820 {
821     if(!canvas) return;
822     if(canvas->canvasType)
823     {
824         CanvasOptionsChanged();
825     }
826     else
827     {
828     }
829     canvas->ResizeEvent();
830
831     CanvasMoveEvent();
832 }
833
834 void MLDemos::ClusterChanged()
835 {
836     if(optionsCluster->optimizeCombo->currentIndex() == 3) // F1
837     {
838         optionsCluster->trainRatioCombo->setVisible(true);
839     }
840     else
841     {
842         optionsCluster->trainRatioCombo->setVisible(false);
843     }
844 }
845
846 void MLDemos::AlgoChanged()
847 {
848     ChangeInfoFile();
849     actionAlgorithms->setChecked(algorithmWidget->isVisible());
850     if(algorithmOptions->tabMax->isVisible())
851     {
852         drawToolbar->paintButton->setChecked(true);
853         DrawPaint();
854     }
855     if(algorithmOptions->tabDyn->isVisible())
856     {
857         drawToolbar->trajectoryButton->setChecked(true);
858         DrawTrajectory();
859     }
860     if(algorithmOptions->tabRegr->isVisible() || algorithmOptions->tabClass->isVisible() || algorithmOptions->tabClust->isVisible() || algorithmOptions->tabProj->isVisible())
861     {
862         drawToolbar->sprayButton->setChecked(true);
863         DrawSpray();
864     }
865 }
866
867 void MLDemos::CompareAdd()
868 {
869     if(algorithmOptions->tabClass->isVisible())
870     {
871         int tab = optionsClassify->tabWidget->currentIndex();
872         QString name = classifiers[tab]->GetAlgoString();
873         QString parameterData;
874         QTextStream stream(&parameterData, QIODevice::WriteOnly);
875         stream << "Classification" << ":" << tab << "\n";
876         classifiers[tab]->SaveParams(stream);
877         optionsCompare->algoList->addItem(name);
878         compareOptions.push_back(parameterData);
879     }
880     if(algorithmOptions->tabRegr->isVisible())
881     {
882         int tab = optionsRegress->tabWidget->currentIndex();
883         QString name = regressors[tab]->GetAlgoString();
884         QString parameterData;
885         QTextStream stream(&parameterData, QIODevice::WriteOnly);
886         stream << "Regression" << ":" << tab << "\n";
887         regressors[tab]->SaveParams(stream);
888         optionsCompare->algoList->addItem(name);
889         compareOptions.push_back(parameterData);
890     }
891     if(algorithmOptions->tabDyn->isVisible())
892     {
893         int tab = optionsDynamic->tabWidget->currentIndex();
894         QString name = dynamicals[tab]->GetAlgoString();
895         QString parameterData;
896         QTextStream stream(&parameterData, QIODevice::WriteOnly);
897         stream << "Dynamical" << ":" << tab << "\n";
898         dynamicals[tab]->SaveParams(stream);
899         optionsCompare->algoList->addItem(name);
900         compareOptions.push_back(parameterData);
901     }
902     if(algorithmOptions->tabMax->isVisible())
903     {
904         int tab = optionsMaximize->tabWidget->currentIndex();
905         QString name = maximizers[tab]->GetAlgoString();
906         QString parameterData;
907         QTextStream stream(&parameterData, QIODevice::WriteOnly);
908         stream << "Optimization" << ":" << tab << "\n";
909         maximizers[tab]->SaveParams(stream);
910         optionsCompare->algoList->addItem(name);
911         compareOptions.push_back(parameterData);
912     }
913     actionCompare->setChecked(true);
914     compareWidget->show();
915 }
916
917 void MLDemos::CompareClear()
918 {
919     optionsCompare->algoList->clear();
920     compareOptions.clear();
921     if(compareDisplay) compareDisplay->hide();
922 }
923
924 void MLDemos::CompareRemove()
925 {
926     int offset = 0;
927     FOR(i, optionsCompare->algoList->count())
928     {
929         if(optionsCompare->algoList->item(i)->isSelected())
930         {
931             compareOptions.removeAt(i-offset);
932             offset++;
933         }
934     }
935
936     QList<QListWidgetItem *> selected = optionsCompare->algoList->selectedItems();
937     FOR(i, selected.size()) delete selected[i];
938     if(optionsCompare->algoList->count()) optionsCompare->algoList->item(0)->setSelected(true);
939 }
940
941 void MLDemos::ShowAlgorithmOptions()
942 {
943     if(actionAlgorithms->isChecked()) algorithmWidget->show();
944     else algorithmWidget->hide();
945 }
946
947 void MLDemos::ShowOptionCompare()
948 {
949     if(actionCompare->isChecked())
950     {
951         compareWidget->show();
952     }
953     else
954     {
955         compareWidget->hide();
956     }
957 }
958
959 void MLDemos::ShowSampleDrawing()
960 {
961     if(actionDrawSamples->isChecked())
962     {
963         drawToolbarWidget->show();
964     }
965     else
966     {
967         drawToolbarWidget->hide();
968     }
969 }
970
971 void MLDemos::ShowAddData()
972 {
973     if(actionAddData->isChecked())
974     {
975         generator->show();
976     }
977     else
978     {
979         generator->hide();
980     }
981 }
982
983 void MLDemos::HideAddData()
984 {
985     generator->hide();
986     actionAddData->setChecked(false);
987 }
988
989 void MLDemos::ShowOptionDisplay()
990 {
991     if(actionDisplayOptions->isChecked()) displayDialog->show();
992     else displayDialog->hide();
993 }
994
995 void MLDemos::ShowToolbar()
996 {
997     if(ui.actionSmall_Icons->isChecked())
998     {
999         toolBar->setIconSize(QSize(32,32));
1000         toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
1001     }
1002     else
1003     {
1004         toolBar->setIconSize(QSize(64,64));
1005         toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
1006     }
1007     if(ui.actionShow_Toolbar->isChecked()) toolBar->show();
1008     else toolBar->hide();
1009 }
1010
1011 void MLDemos::ShowStatsDialog()
1012 {
1013     if(actionShowStats->isChecked()) statsDialog->show();
1014     else statsDialog->hide();
1015 }
1016
1017 void MLDemos::ShowAbout()
1018 {
1019     about->show();
1020 }
1021
1022 void MLDemos::ManualSelection()
1023 {
1024     manualSelectDialog->show();
1025 }
1026
1027 void MLDemos::InputDimensions()
1028 {
1029     inputDimensionsDialog->show();
1030 }
1031
1032 void MLDemos::HideSampleDrawing()
1033 {
1034     drawToolbarWidget->hide();
1035     actionDrawSamples->setChecked(false);
1036 }
1037
1038 void MLDemos::HideOptionDisplay()
1039 {
1040     displayDialog->hide();
1041     actionDisplayOptions->setChecked(false);
1042 }
1043
1044 void MLDemos::HideToolbar()
1045 {
1046     toolBar->hide();
1047     ui.actionShow_Toolbar->setChecked(false);
1048 }
1049
1050 void MLDemos::HideStatsDialog()
1051 {
1052     statsDialog->hide();
1053     actionShowStats->setChecked(false);
1054 }
1055
1056 void MLDemos::Clear()
1057 {
1058     drawTimer->Stop();
1059     drawTimer->Clear();
1060     QMutexLocker lock(&mutex);
1061     qApp->processEvents();
1062     DEL(classifier);
1063     DEL(regressor);
1064     DEL(dynamical);
1065     DEL(clusterer);
1066     DEL(maximizer);
1067     DEL(projector);
1068     canvas->maps.confidence = QPixmap();
1069     canvas->maps.model = QPixmap();
1070     canvas->maps.info = QPixmap();
1071     canvas->liveTrajectory.clear();
1072     canvas->sampleColors.clear();
1073     canvas->maps.animation = QPixmap();
1074     canvas->repaint();
1075     UpdateInfo();
1076 }
1077
1078 void MLDemos::ResetPositiveClass()
1079 {
1080     int labMin = INT_MAX, labMax = INT_MIN;
1081     if(!canvas->data->GetCount())
1082     {
1083         labMin = 0;
1084         labMax = 1;
1085     }
1086     else
1087     {
1088         ivec labels = canvas->data->GetLabels();
1089         FOR(i, labels.size())
1090         {
1091             if(labels[i] > labMax) labMax = labels[i];
1092             if(labels[i] < labMin) labMin = labels[i];
1093         }
1094     }
1095     int dimCount = max(2,canvas->data->GetDimCount());
1096     int currentOutputDim = optionsCompare->outputDimCombo->currentIndex();
1097
1098     optionsCompare->outputDimCombo->clear();
1099     optionsRegress->outputDimCombo->clear();
1100     FOR(i, dimCount)
1101     {
1102         if(i < canvas->dimNames.size())
1103         {
1104             optionsCompare->outputDimCombo->addItem(QString("%1) %2").arg(i+1).arg(canvas->dimNames.at(i)));
1105             optionsRegress->outputDimCombo->addItem(QString("%1) %2").arg(i+1).arg(canvas->dimNames.at(i)));
1106         }
1107         else
1108         {
1109             optionsCompare->outputDimCombo->addItem(QString("%1").arg(i+1));
1110             optionsRegress->outputDimCombo->addItem(QString("%1").arg(i+1));
1111         }
1112     }
1113     if(currentOutputDim < dimCount) optionsCompare->outputDimCombo->setCurrentIndex(currentOutputDim);
1114
1115     optionsClassify->positiveSpin->setRange(labMin,labMax);
1116     if(optionsClassify->positiveSpin->value() < labMin)
1117         optionsClassify->positiveSpin->setValue(labMin);
1118     else if(optionsClassify->positiveSpin->value() > labMax)
1119         optionsClassify->positiveSpin->setValue(labMax);
1120     ui.canvasX1Spin->setRange(1,dimCount);
1121     ui.canvasX2Spin->setRange(1,dimCount);
1122     ui.canvasX3Spin->setRange(0,dimCount);
1123     canvas->SetDim(ui.canvasX1Spin->value()-1,ui.canvasX2Spin->value()-1, ui.canvasX3Spin->value()-1);
1124     ManualSelectionUpdated();
1125     InputDimensionsUpdated();
1126 }
1127
1128 void MLDemos::ChangeActiveOptions()
1129 {
1130     DisplayOptionChanged();
1131 }
1132
1133 void MLDemos::ClearData()
1134 {
1135     sourceData.clear();
1136     sourceLabels.clear();
1137     projectedData.clear();
1138     if(canvas)
1139     {
1140         canvas->dimNames.clear();
1141         canvas->sampleColors.clear();
1142         canvas->data->Clear();
1143         canvas->targets.clear();
1144         canvas->targetAge.clear();
1145         canvas->maps.animation = QPixmap();
1146         canvas->maps.reward = QPixmap();
1147         canvas->maps.samples = QPixmap();
1148         canvas->maps.trajectories = QPixmap();
1149         canvas->maps.grid = QPixmap();
1150     }
1151     Clear();
1152     ResetPositiveClass();
1153     FitToData();
1154     ManualSelectionUpdated();
1155     UpdateInfo();
1156 }
1157
1158 void MLDemos::ShiftDimensions()
1159 {
1160     if(canvas)
1161     {
1162         vector<fvec> samples = canvas->data->GetSamples();
1163         if(!samples.size()) return;
1164         int dim = samples[0].size();
1165         if(dim < 2) return;
1166         FOR(i, samples.size())
1167         {
1168             float tmp = samples[i][0];
1169             FOR(d, dim-1)
1170             {
1171                 samples[i][d] = samples[i][d+1];
1172             }
1173             samples[i][dim-1] = tmp;
1174         }
1175         canvas->data->SetSamples(samples);
1176     }
1177     DisplayOptionChanged();
1178 }
1179
1180
1181 void MLDemos::DrawNone()
1182 {
1183     drawToolbar->singleButton->setChecked(false);
1184     drawToolbar->sprayButton->setChecked(false);
1185     drawToolbar->eraseButton->setChecked(false);
1186     drawToolbar->ellipseButton->setChecked(false);
1187     drawToolbar->lineButton->setChecked(false);
1188     drawToolbar->trajectoryButton->setChecked(false);
1189     drawToolbar->obstacleButton->setChecked(false);
1190     drawToolbar->paintButton->setChecked(false);
1191 }
1192
1193 void MLDemos::DrawSingle()
1194 {
1195     if(drawToolbar->singleButton->isChecked())
1196     {
1197         drawToolbar->sprayButton->setChecked(false);
1198         drawToolbar->eraseButton->setChecked(false);
1199         drawToolbar->ellipseButton->setChecked(false);
1200         drawToolbar->lineButton->setChecked(false);
1201         drawToolbar->trajectoryButton->setChecked(false);
1202         drawToolbar->obstacleButton->setChecked(false);
1203         drawToolbar->paintButton->setChecked(false);
1204     }
1205 }
1206
1207 void MLDemos::DrawSpray()
1208 {
1209     if(drawToolbar->sprayButton->isChecked())
1210     {
1211         drawToolbar->singleButton->setChecked(false);
1212         drawToolbar->eraseButton->setChecked(false);
1213         drawToolbar->ellipseButton->setChecked(false);
1214         drawToolbar->lineButton->setChecked(false);
1215         drawToolbar->trajectoryButton->setChecked(false);
1216         drawToolbar->obstacleButton->setChecked(false);
1217         drawToolbar->paintButton->setChecked(false);
1218     }
1219 }
1220
1221 void MLDemos::DrawErase()
1222 {
1223     if(drawToolbar->eraseButton->isChecked())
1224     {
1225         drawToolbar->singleButton->setChecked(false);
1226         drawToolbar->sprayButton->setChecked(false);
1227         drawToolbar->ellipseButton->setChecked(false);
1228         drawToolbar->lineButton->setChecked(false);
1229         drawToolbar->trajectoryButton->setChecked(false);
1230         drawToolbar->obstacleButton->setChecked(false);
1231         drawToolbar->paintButton->setChecked(false);
1232     }
1233 }
1234
1235 void MLDemos::DrawLine()
1236 {
1237     if(drawToolbar->lineButton->isChecked())
1238     {
1239         drawToolbar->singleButton->setChecked(false);
1240         drawToolbar->sprayButton->setChecked(false);
1241         drawToolbar->ellipseButton->setChecked(false);
1242         drawToolbar->eraseButton->setChecked(false);
1243         drawToolbar->trajectoryButton->setChecked(false);
1244         drawToolbar->obstacleButton->setChecked(false);
1245         drawToolbar->paintButton->setChecked(false);
1246     }
1247 }
1248
1249 void MLDemos::DrawEllipse()
1250 {
1251     if(drawToolbar->ellipseButton->isChecked())
1252     {
1253         drawToolbar->singleButton->setChecked(false);
1254         drawToolbar->sprayButton->setChecked(false);
1255         drawToolbar->eraseButton->setChecked(false);
1256         drawToolbar->lineButton->setChecked(false);
1257         drawToolbar->trajectoryButton->setChecked(false);
1258         drawToolbar->obstacleButton->setChecked(false);
1259         drawToolbar->paintButton->setChecked(false);
1260     }
1261 }
1262
1263 void MLDemos::DrawTrajectory()
1264 {
1265     if(drawToolbar->trajectoryButton->isChecked())
1266     {
1267         drawToolbar->singleButton->setChecked(false);
1268         drawToolbar->sprayButton->setChecked(false);
1269         drawToolbar->eraseButton->setChecked(false);
1270         drawToolbar->lineButton->setChecked(false);
1271         drawToolbar->ellipseButton->setChecked(false);
1272         drawToolbar->obstacleButton->setChecked(false);
1273         drawToolbar->paintButton->setChecked(false);
1274     }
1275 }
1276
1277 void MLDemos::DrawObstacle()
1278 {
1279     if(drawToolbar->obstacleButton->isChecked())
1280     {
1281         drawToolbar->eraseButton->setChecked(false);
1282         drawToolbar->singleButton->setChecked(false);
1283         drawToolbar->sprayButton->setChecked(false);
1284         drawToolbar->ellipseButton->setChecked(false);
1285         drawToolbar->lineButton->setChecked(false);
1286         drawToolbar->trajectoryButton->setChecked(false);
1287         drawToolbar->paintButton->setChecked(false);
1288     }
1289 }
1290
1291 void MLDemos::DrawPaint()
1292 {
1293     if(drawToolbar->paintButton->isChecked())
1294     {
1295         drawToolbar->eraseButton->setChecked(false);
1296         drawToolbar->singleButton->setChecked(false);
1297         drawToolbar->sprayButton->setChecked(false);
1298         drawToolbar->ellipseButton->setChecked(false);
1299         drawToolbar->lineButton->setChecked(false);
1300         drawToolbar->trajectoryButton->setChecked(false);
1301         drawToolbar->obstacleButton->setChecked(false);
1302     }
1303 }
1304
1305 void MLDemos::AvoidOptionChanged()
1306 {
1307     if(dynamical)
1308     {
1309         int avoidIndex = optionsDynamic->obstacleCombo->currentIndex();
1310         mutex.lock();
1311         if(dynamical->avoid) delete dynamical->avoid;
1312         if(!avoidIndex) dynamical->avoid = 0;
1313         else dynamical->avoid = avoiders[avoidIndex-1]->GetObstacleAvoidance();
1314         mutex.unlock();
1315         drawTimer->Stop();
1316         drawTimer->Clear();
1317         drawTimer->start(QThread::NormalPriority);
1318     }
1319 }
1320
1321 void MLDemos::ColorMapChanged()
1322 {
1323     if(dynamical)
1324     {
1325         drawTimer->Stop();
1326         drawTimer->Clear();
1327         drawTimer->bColorMap = optionsDynamic->colorCheck->isChecked();
1328         drawTimer->start(QThread::NormalPriority);
1329     }
1330 }
1331
1332 void MLDemos::DisplayOptionChanged()
1333 {
1334     if(!canvas) return;
1335
1336     canvas->bDisplayInfo = displayOptions->infoCheck->isChecked();
1337     canvas->bDisplayLearned = displayOptions->modelCheck->isChecked();
1338     canvas->bDisplayMap = displayOptions->mapCheck->isChecked();
1339     canvas->bDisplaySamples = displayOptions->samplesCheck->isChecked();
1340     canvas->bDisplayTrajectories = displayOptions->samplesCheck->isChecked();
1341     canvas->bDisplayTimeSeries = displayOptions->samplesCheck->isChecked();
1342     canvas->bDisplayGrid = displayOptions->gridCheck->isChecked();
1343     canvas->bDisplayLegend = displayOptions->legendCheck->isChecked();
1344     {
1345         int xIndex = ui.canvasX1Spin->value()-1;
1346         int yIndex = ui.canvasX2Spin->value()-1;
1347         int zIndex = ui.canvasX3Spin->value()-1;
1348         canvas->SetDim(xIndex, yIndex, zIndex);
1349     }
1350     float zoom = displayOptions->spinZoom->value();
1351     if(zoom >= 0.f) zoom += 1.f;
1352     else zoom = 1.f / (fabs(zoom)+1.f);
1353     if(zoom != canvas->GetZoom())
1354     {
1355         drawTimer->Stop();
1356         drawTimer->Clear();
1357         canvas->SetZoom(zoom);
1358         if(mutex.tryLock())
1359         {
1360             if(!canvas->canvasType)
1361             {
1362                 if(classifier)
1363                 {
1364                     classifiers[tabUsedForTraining]->Draw(canvas, classifier);
1365                     if(classifier->UsesDrawTimer())
1366                     {
1367                         drawTimer->start(QThread::NormalPriority);
1368                     }
1369                 }
1370                 else if(regressor)
1371                 {
1372                     regressors[tabUsedForTraining]->Draw(canvas, regressor);
1373                     //drawTimer->start(QThread::NormalPriority);
1374                 }
1375                 else if(clusterer)
1376                 {
1377                     clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
1378                 }
1379                 else if(dynamical)
1380                 {
1381                     dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
1382                     if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
1383                 }
1384                 else if(maximizer)
1385                 {
1386                     drawTimer->start(QThread::NormalPriority);
1387                 }
1388             }
1389             if(projector)
1390             {
1391                 projectors[tabUsedForTraining]->Draw(canvas, projector);
1392             }
1393             mutex.unlock();
1394         }
1395         canvas->repaint();
1396     }
1397     //  canvas->bDisplayTrajectories = displayOptions->trajectoriesCheck->isChecked();
1398     if(optionsDynamic)
1399     {
1400         canvas->trajectoryCenterType = optionsDynamic->centerCombo->currentIndex();
1401         canvas->trajectoryResampleType = optionsDynamic->resampleCombo->currentIndex();
1402         canvas->trajectoryResampleCount = optionsDynamic->resampleSpin->value();
1403     }
1404     CanvasTypeChanged();
1405     CanvasOptionsChanged();
1406     canvas->ResetSamples();
1407     canvas->repaint();
1408 }
1409
1410 void MLDemos::ChangeInfoFile()
1411 {
1412     QString infoFile;
1413     if(algorithmOptions->tabClass->isVisible())
1414     {
1415         int tab = optionsClassify->tabWidget->currentIndex();
1416         if(tab < 0 || tab >= (int)classifiers.size() || !classifiers[tab]) return;
1417         infoFile = classifiers[tab]->GetInfoFile();
1418     }
1419     if(algorithmOptions->tabClust->isVisible())
1420     {
1421         int tab = optionsCluster->tabWidget->currentIndex();
1422         if(tab < 0 || tab >= (int)clusterers.size() || !clusterers[tab]) return;
1423         infoFile = clusterers[tab]->GetInfoFile();
1424     }
1425     if(algorithmOptions->tabRegr->isVisible())
1426     {
1427         int tab = optionsRegress->tabWidget->currentIndex();
1428         if(tab < 0 || tab >= (int)regressors.size() || !regressors[tab]) return;
1429         infoFile = regressors[tab]->GetInfoFile();
1430     }
1431     if(algorithmOptions->tabDyn->isVisible())
1432     {
1433         int tab = optionsDynamic->tabWidget->currentIndex();
1434         if(tab < 0 || tab >= (int)dynamicals.size() || !dynamicals[tab]) return;
1435         infoFile = dynamicals[tab]->GetInfoFile();
1436     }
1437     if(algorithmOptions->tabMax->isVisible())
1438     {
1439         int tab = optionsMaximize->tabWidget->currentIndex();
1440         if(tab < 0 || tab >= (int)maximizers.size() || !maximizers[tab]) return;
1441         infoFile = maximizers[tab]->GetInfoFile();
1442     }
1443     if(algorithmOptions->tabProj->isVisible())
1444     {
1445         int tab = optionsProject->tabWidget->currentIndex();
1446         if(tab < 0 || tab >= (int)projectors.size() || !projectors[tab]) return;
1447         infoFile = projectors[tab]->GetInfoFile();
1448     }
1449     if(infoFile == "") infoFile = "mldemos.html"; // we want the main information page
1450
1451     QDir helpDir = QDir(qApp->applicationDirPath());
1452     QDir alternativeDir = helpDir;
1453 #if defined(Q_OS_WIN)
1454     if (helpDir.dirName().toLower() == "debug" || helpDir.dirName().toLower() == "release") helpDir.cdUp();
1455 #elif defined(Q_OS_MAC)
1456     if (helpDir.dirName() == "MacOS") {
1457         if(!helpDir.cd("help"))
1458         {
1459             helpDir.cdUp();
1460             helpDir.cdUp();
1461             helpDir.cdUp();
1462             alternativeDir = helpDir;
1463         }
1464         else helpDir.cdUp();
1465     }
1466 #endif
1467     if(!helpDir.cd("help"))
1468     {
1469         //qDebug() << "using alternative directory: " << alternativeDir.absolutePath();
1470         helpDir = alternativeDir;
1471         if(!helpDir.cd("help")) return;
1472     }
1473     //qDebug() << "using help directory: " << helpDir.absolutePath();
1474
1475     QString filePath(helpDir.absolutePath() + "/" + infoFile);
1476     //qDebug() << "loading info from: " << filePath;
1477     showStats->algoText->clear();
1478     showStats->algoText->setSource(QUrl::fromLocalFile(filePath));
1479 }
1480
1481 void MLDemos::ManualSelectionUpdated()
1482 {
1483     if(!canvas) return;
1484     // we add the samples
1485     vector<fvec> samples = canvas->data->GetSamples();
1486     int dim = samples.size() ? samples[0].size() : 0;
1487     ivec labels = canvas->data->GetLabels();
1488     manualSelection->sampleList->clear();
1489     FOR(i, samples.size())
1490     {
1491         QString item = QString("%1: (%2)").arg(i+1).arg(labels[i]);
1492         FOR(d, dim) item += QString(" %1").arg(samples[i][d], 0, 'f', 2);
1493         manualSelection->sampleList->addItem(item);
1494     }
1495     ManualSelectionChanged();
1496 }
1497
1498 void MLDemos::ManualSelectionChanged()
1499 {
1500     int count = manualSelection->sampleList->count();
1501     int trainCount = count, testCount = 0;
1502     QList<QListWidgetItem*> selected = manualSelection->sampleList->selectedItems();
1503     if(selected.size())
1504     {
1505         trainCount = selected.size();
1506         testCount = count - trainCount;
1507     }
1508     manualSelection->TrainLabel->setText(QString("Train: %1").arg(trainCount));
1509     manualSelection->TestLabel->setText(QString("Test: %1").arg(testCount));
1510 }
1511
1512 void MLDemos::ManualSelectionClear()
1513 {
1514     manualSelection->sampleList->clearSelection();
1515     ManualSelectionChanged();
1516 }
1517
1518 void MLDemos::ManualSelectionInvert()
1519 {
1520     FOR(i, manualSelection->sampleList->count())
1521     {
1522         manualSelection->sampleList->item(i)->setSelected(!manualSelection->sampleList->item(i)->isSelected());
1523     }
1524     ManualSelectionChanged();
1525 }
1526
1527 void MLDemos::ManualSelectionRandom()
1528 {
1529     float ratio = (manualSelection->randomCombo->currentIndex()+1.f)/10.f;
1530     manualSelection->sampleList->clearSelection();
1531     u32* perm = randPerm(manualSelection->sampleList->count());
1532     FOR(i, ratio*manualSelection->sampleList->count())
1533     {
1534         manualSelection->sampleList->item(perm[i])->setSelected(true);
1535     }
1536     KILL(perm);
1537     ManualSelectionChanged();
1538 }
1539
1540 void MLDemos::ManualSelectionRemove()
1541 {
1542     if(!canvas || !canvas->data->GetCount()) return;
1543     QList<QListWidgetItem*> selected = manualSelection->sampleList->selectedItems();
1544     if(!selected.size()) return;
1545     ivec removeList(selected.count());
1546     FOR(i, selected.count())
1547     {
1548         removeList[i] = manualSelection->sampleList->row(selected[i]);
1549     }
1550     canvas->data->RemoveSamples(removeList);
1551     if(canvas->sampleColors.size() && removeList.size() < canvas->sampleColors.size())
1552     {
1553         int offset = 0;
1554         FOR(i, removeList.size())
1555         {
1556             int index = i - offset;
1557             if(index < 0 || index >= canvas->sampleColors.size()) continue;
1558             canvas->sampleColors.erase(canvas->sampleColors.begin()+index);
1559             offset++;
1560         }
1561     }
1562     ManualSelectionUpdated();
1563     ManualSelectionChanged();
1564     canvas->ResetSamples();
1565     CanvasOptionsChanged();
1566     canvas->repaint();
1567 }
1568
1569 void MLDemos::InputDimensionsUpdated()
1570 {
1571     if(!canvas) return;
1572     int dim = canvas->data->GetDimCount();
1573     inputDimensions->dimList->clear();
1574     fvec xMin(dim,FLT_MAX), xMax(dim,-FLT_MAX);
1575     vector<fvec> samples = canvas->data->GetSamples();
1576     FOR(i, samples.size())
1577     {
1578         FOR(d, dim)
1579         {
1580             xMin[d] = min(xMin[d], samples[i][d]);
1581             xMax[d] = max(xMax[d], samples[i][d]);
1582         }
1583     }
1584     FOR(d, dim)
1585     {
1586         QString item = QString("%1").arg(d+1);
1587         if(d < canvas->dimNames.size()) item += QString(") %2").arg(canvas->dimNames.at(d));
1588         item += QString(" : [%1 --> %2]").arg(xMin[d], 0, 'f', 3).arg(xMax[d], 0, 'f', 3);
1589         inputDimensions->dimList->addItem(item);
1590     }
1591     ManualSelectionChanged();
1592 }
1593
1594 void MLDemos::InputDimensionsChanged()
1595 {
1596     int count = inputDimensions->dimList->count();
1597     QList<QListWidgetItem*> selected = inputDimensions->dimList->selectedItems();
1598     inputDimensions->TrainLabel->setText(QString("Used: %1").arg(selected.size()));
1599     inputDimensions->TestLabel->setText(QString("Unused: %1").arg(count-selected.size()));
1600 }
1601
1602 void MLDemos::InputDimensionsClear()
1603 {
1604     inputDimensions->dimList->clearSelection();
1605     ManualSelectionChanged();
1606 }
1607
1608 void MLDemos::InputDimensionsInvert()
1609 {
1610     FOR(i, inputDimensions->dimList->count())
1611     {
1612         inputDimensions->dimList->item(i)->setSelected(!inputDimensions->dimList->item(i)->isSelected());
1613     }
1614     ManualSelectionChanged();
1615 }
1616
1617 void MLDemos::InputDimensionsRandom()
1618 {
1619     float ratio = (inputDimensions->randomCombo->currentIndex()+1.f)/10.f;
1620     inputDimensions->dimList->clearSelection();
1621     u32* perm = randPerm(inputDimensions->dimList->count());
1622     FOR(i, ratio*inputDimensions->dimList->count())
1623     {
1624         inputDimensions->dimList->item(perm[i])->setSelected(true);
1625     }
1626     KILL(perm);
1627     ManualSelectionChanged();
1628 }
1629
1630 void MLDemos::DrawCrosshair()
1631 {
1632     int drawType = 0;
1633     if(drawToolbar->singleButton->isChecked()) drawType = 1;
1634     if(drawToolbar->sprayButton->isChecked()) drawType = 2;
1635     if(drawToolbar->eraseButton->isChecked()) drawType = 3;
1636     if(drawToolbar->ellipseButton->isChecked()) drawType = 4;
1637     if(drawToolbar->lineButton->isChecked()) drawType = 5;
1638     if(drawToolbar->trajectoryButton->isChecked()) drawType = 6;
1639     if(drawToolbar->obstacleButton->isChecked()) drawType = 7;
1640     if(drawToolbar->paintButton->isChecked()) drawType = 8;
1641
1642     if(!drawType || drawType == 1 || drawType == 6)
1643     {
1644         canvas->crosshair = QPainterPath();
1645         canvas->bNewCrosshair = false;
1646         return;
1647     }
1648     int type = drawToolbarContext1->randCombo->currentIndex();
1649     float aX = drawToolbarContext2->spinSigmaX->value();
1650     float aY = drawToolbarContext2->spinSigmaY->value();
1651     float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
1652     float s = drawToolbarContext1->spinSize->value();
1653     int size = (int)(s*canvas->height());
1654     int sizeX = (int)(aX*canvas->height());
1655     int Size = canvas->height();
1656
1657     QPainterPath cursor;
1658
1659     float sin_angle = sinf(angle);
1660     float cos_angle = cosf(angle);
1661
1662     switch(drawType)
1663     {
1664     case 5: // line
1665     {
1666         QPointF pStart, pStop;
1667         float x = cos_angle*aX;
1668         float y = sin_angle*aX;
1669         pStart = QPointF(- x*Size, - y*Size);
1670         pStop = QPointF(+ x*Size, + y*Size);
1671         cursor.moveTo(pStart);
1672         cursor.lineTo(pStop);
1673         canvas->crosshair = cursor;
1674         canvas->bNewCrosshair = false;
1675         return;
1676     }
1677         break;
1678     case 2: // spray
1679     case 3: // erase
1680     {
1681         cursor.addEllipse(QPoint(0,0),size/2,size/2);
1682         canvas->crosshair = cursor;
1683         canvas->bNewCrosshair = false;
1684         return;
1685     }
1686         break;
1687     case 7: // obstacles
1688     {
1689         Obstacle o;
1690         o.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf;
1691         o.axes.resize(2);
1692         o.axes[0] = drawToolbarContext3->spinSigmaX->value();
1693         o.axes[1] = drawToolbarContext3->spinSigmaY->value();
1694         o.power[0] = drawToolbarContext3->spinPowerX->value();
1695         o.power[1] = drawToolbarContext3->spinPowerY->value();
1696         o.repulsion[0] = drawToolbarContext3->spinRepulsionX->value();
1697         o.repulsion[1] = drawToolbarContext3->spinRepulsionY->value();
1698         o.center = fVec(0,0);
1699         canvas->crosshair = canvas->DrawObstacle(o);
1700         canvas->bNewCrosshair = false;
1701         return;
1702     }
1703         break;
1704     case 8: // paint
1705     {
1706         float radius = drawToolbarContext4->spinRadius->value();
1707         QPainterPath cursor;
1708         cursor.addEllipse(QPoint(0,0),radius,radius);
1709         canvas->crosshair = cursor;
1710         canvas->bNewCrosshair = false;
1711         return;
1712     }
1713         break;
1714     }
1715
1716     QPointF oldPoint, point;
1717     for(float theta=0; theta < 2*PIf + 0.1; theta += 0.1f)
1718     {
1719         float X, Y;
1720         if(drawType == 2 || drawType == 3)
1721         {
1722             X = sqrtf(aX)/2 * cosf(theta);
1723             Y = sqrtf(aY)/2 * sinf(theta);
1724         }
1725         else
1726         {
1727             X = aX * cosf(theta);
1728             Y = aY * sinf(theta);
1729         }
1730
1731         float RX = + X * cos_angle + Y * sin_angle;
1732         float RY = - X * sin_angle + Y * cos_angle;
1733
1734         point = QPointF(RX*Size,RY*Size);
1735         if(theta==0)
1736         {
1737             cursor.moveTo(point);
1738             continue;
1739         }
1740         cursor.lineTo(point);
1741         oldPoint = point;
1742     }
1743     canvas->crosshair = cursor;
1744     canvas->bNewCrosshair = false;
1745 }
1746
1747 void MLDemos::Drawing( fvec sample, int label)
1748 {
1749     if(canvas->canvasType) return;
1750     int drawType = 0; // none
1751     if(drawToolbar->singleButton->isChecked()) drawType = 1;
1752     if(drawToolbar->sprayButton->isChecked()) drawType = 2;
1753     if(drawToolbar->eraseButton->isChecked()) drawType = 3;
1754     if(drawToolbar->ellipseButton->isChecked()) drawType = 4;
1755     if(drawToolbar->lineButton->isChecked()) drawType = 5;
1756     if(drawToolbar->trajectoryButton->isChecked()) drawType = 6;
1757     if(drawToolbar->obstacleButton->isChecked()) drawType = 7;
1758     if(drawToolbar->paintButton->isChecked()) drawType = 8;
1759     if(!drawType) return;
1760
1761     int speed = 6;
1762
1763     if(label) label = drawToolbar->classSpin->value();
1764
1765     switch(drawType)
1766     {
1767     case 1: // single samples
1768     {
1769         // we don't want to draw too often
1770         if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing
1771         canvas->data->AddSample(sample, label);
1772     }
1773         break;
1774     case 2: // spray samples
1775     {
1776         // we don't want to draw too often
1777         if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
1778         int type = drawToolbarContext1->randCombo->currentIndex();
1779         float s = drawToolbarContext1->spinSize->value();
1780         float size = s*canvas->height();
1781         int count = drawToolbarContext1->spinCount->value();
1782
1783         QPointF sampleCoords = canvas->toCanvasCoords(sample);
1784         // we generate the new data
1785         float variance = sqrtf(size*size/9.f*0.5f);
1786         fvec newSample; newSample.resize(2,0);
1787         FOR(i, count)
1788         {
1789             if(type == 0) // uniform
1790             {
1791                 newSample[0] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.x();
1792                 newSample[1] = (rand()/(float)RAND_MAX - 0.5f)*size + sampleCoords.y();
1793             }
1794             else // normal
1795             {
1796                 newSample[0] = RandN((float)sampleCoords.x(), variance);
1797                 newSample[1] = RandN((float)sampleCoords.y(), variance);
1798             }
1799             fvec canvasSample = canvas->toSampleCoords(newSample[0],newSample[1]);
1800             //canvasSample.push_back(label ? RandN(1.f,0.5f) : RandN(-1.f,0.5f));
1801             //canvasSample.push_back(label ? RandN(-.5f,0.5f) : RandN(.5f,0.5f));
1802             canvas->data->AddSample(canvasSample, label);
1803         }
1804     }
1805         break;
1806     case 3: // erase
1807     {
1808         float s = drawToolbarContext1->spinSize->value();
1809         float size = s*canvas->height();
1810         QPointF center = canvas->toCanvasCoords(sample);
1811         bool anythingDeleted = canvas->DeleteData(center, size/2);
1812         if(anythingDeleted)
1813         {
1814             drawTimer->Stop();
1815             drawTimer->Clear();
1816             QMutexLocker lock(&mutex);
1817             if(dynamical && dynamical->avoid) dynamical->avoid->SetObstacles(canvas->data->GetObstacles());
1818             drawTimer->start(QThread::NormalPriority);
1819             canvas->ResetSamples();
1820         }
1821     }
1822         break;
1823     case 4: // ellipse
1824     {
1825         if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
1826         float aX = drawToolbarContext2->spinSigmaX->value();
1827         float aY = drawToolbarContext2->spinSigmaY->value();
1828         float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
1829         int count = drawToolbarContext1->spinCount->value()+1;
1830         float sin_angle = sinf(angle);
1831         float cos_angle = cosf(angle);
1832
1833         QPointF oldPoint, point;
1834         float startTheta = rand()/(float)RAND_MAX*2*PIf;
1835         for(float theta=0; theta < 2*PIf; theta += 2.f*PIf/count)
1836         {
1837             float X = aX * cosf(theta+startTheta);
1838             float Y = aY * sinf(theta+startTheta);
1839
1840             float RX = + X * cos_angle + Y * sin_angle;
1841             float RY = - X * sin_angle + Y * cos_angle;
1842
1843             fvec newSample;
1844             newSample.resize(2,0);
1845             newSample[0] = sample[0] + RX;
1846             newSample[1] = sample[1] + RY;
1847             if(theta==0)
1848             {
1849                 oldPoint = point;
1850                 continue;
1851             }
1852             canvas->data->AddSample(newSample, label);
1853
1854             oldPoint = point;
1855         }
1856     }
1857         break;
1858     case 5: // line
1859     {
1860         if(drawTime.elapsed() < 200/speed) return; // msec elapsed since last drawing
1861         float aX = drawToolbarContext2->spinSigmaX->value();
1862         float angle = -drawToolbarContext2->spinAngle->value()/180.f*PIf;
1863         int count = drawToolbarContext1->spinCount->value();
1864         float sin_angle = sinf(angle);
1865         float cos_angle = cosf(angle);
1866
1867         QPointF pStart, pStop;
1868         float x = cos_angle*aX;
1869         float y = sin_angle*aX;
1870         pStart = QPointF(sample[0] - x, sample[1] - y);
1871         pStop = QPointF(sample[0] + x, sample[1] + y);
1872         QPointF oldPoint = pStart;
1873         float start = (rand() / (float)RAND_MAX - 0.5) * (1/(float)count);
1874         FOR(i,count)
1875         {
1876             QPointF point = (pStop - pStart)*((i+1)/(float)count + start) + pStart;
1877             fvec newSample;
1878             newSample.resize(2);
1879             newSample[0] = point.x();
1880             newSample[1] = point.y();
1881             canvas->data->AddSample(newSample, label);
1882             oldPoint = point;
1883         }
1884     }
1885         break;
1886     case 6: // trajectory
1887     {
1888         if(trajectory.first == -1) // we're starting a trajectory
1889         {
1890             trajectory.first = canvas->data->GetCount();
1891         }
1892         // we don't want to draw too often
1893         //if(drawTime.elapsed() < 50/speed) return; // msec elapsed since last drawing
1894         canvas->data->AddSample(sample, label, _TRAJ);
1895         trajectory.second = canvas->data->GetCount()-1;
1896     }
1897         break;
1898     case 7: // obstacle
1899     {
1900         bNewObstacle = true;
1901         obstacle = Obstacle();
1902         obstacle.angle = drawToolbarContext3->spinAngle->value() / 180.f * PIf;
1903         obstacle.power[0] = drawToolbarContext3->spinPowerX->value();
1904         obstacle.power[1] = drawToolbarContext3->spinPowerY->value();
1905         obstacle.center = sample;
1906         obstacle.axes[0] = drawToolbarContext3->spinSigmaX->value();
1907         obstacle.axes[1] = drawToolbarContext3->spinSigmaY->value();
1908         obstacle.repulsion[0] = drawToolbarContext3->spinRepulsionX->value();
1909         obstacle.repulsion[1] = drawToolbarContext3->spinRepulsionX->value();
1910     }
1911         break;
1912     case 8: // paint rewards
1913     {
1914         float radius = drawToolbarContext4->spinRadius->value();
1915         float alpha = drawToolbarContext4->spinAlpha->value();
1916         canvas->PaintReward(sample, radius, label ? alpha : -alpha);
1917         /*
1918   // if we need to initialize the reward map
1919   if(!canvas->data->GetReward()->rewards)
1920   {
1921    ivec size;
1922    size.resize(2, 64);
1923    int length = size[0]*size[1];
1924    float *values = new float[length];
1925    FOR(i, length) values[i] = rand()/(float)RAND_MAX - 0.5f;
1926    canvas->data->GetReward()->SetReward(values, size, canvas->canvasTopLeft(), canvas->canvasBottomRight());
1927    delete [] values;
1928   }
1929   canvas->data->GetReward()->ShiftValueAt(sample, 0.2, label ? 0.33 : -0.33);
1930   //qDebug() << canvas->data->GetReward()->ValueAt(sample);
1931   */
1932     }
1933         break;
1934     }
1935     canvas->repaint();
1936     drawTime.restart();
1937     ResetPositiveClass();
1938     ManualSelectionUpdated();
1939     UpdateInfo();
1940 }
1941
1942 void MLDemos::DrawingStopped()
1943 {
1944     if(trajectory.first != -1)
1945     {
1946         // the last point is a duplicate, we take it out
1947         canvas->data->AddSequence(trajectory);
1948         canvas->drawnTrajectories = 0;
1949         trajectory.first = -1;
1950         canvas->repaint();
1951     }
1952     if(bNewObstacle)
1953     {
1954         bNewObstacle = false;
1955         canvas->data->AddObstacle(obstacle);
1956         canvas->repaint();
1957         if(dynamical && dynamical->avoid)
1958         {
1959             drawTimer->Stop();
1960             drawTimer->Clear();
1961             drawTimer->start(QThread::NormalPriority);
1962         }
1963     }
1964 }
1965
1966 void MLDemos::ExposeData()
1967 {
1968     if(!expose) return;
1969     if(!canvas->data->GetCount()) return;
1970     //    if(!canvas->data->GetSamples()[0].size() <= 2) return;
1971     expose->show();
1972     expose->repaint();
1973 }
1974
1975 void MLDemos::FitToData()
1976 {
1977     canvas->FitToData();
1978     float zoom = canvas->GetZoom();
1979     if(zoom >= 1) zoom -=1;
1980     else zoom = 1/(-zoom) - 1;
1981     if(zoom == displayOptions->spinZoom->value())
1982     {
1983         DisplayOptionChanged();
1984         return;
1985     }
1986     displayOptions->spinZoom->blockSignals(true);
1987     displayOptions->spinZoom->setValue(zoom);
1988     displayOptions->spinZoom->blockSignals(false);
1989     drawTimer->Stop();
1990     drawTimer->Clear();
1991     if(!canvas->canvasType)
1992     {
1993         QMutexLocker lock(&mutex);
1994         if(classifier)
1995         {
1996             classifiers[tabUsedForTraining]->Draw(canvas, classifier);
1997             if(classifier->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
1998         }
1999         else if(regressor)
2000         {
2001             regressors[tabUsedForTraining]->Draw(canvas, regressor);
2002             //drawTimer->start(QThread::NormalPriority);
2003         }
2004         else if(clusterer)
2005         {
2006             clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
2007             drawTimer->start(QThread::NormalPriority);
2008         }
2009         else if(dynamical)
2010         {
2011             dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
2012             if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
2013         }
2014         else if(projector)
2015         {
2016             projectors[tabUsedForTraining]->Draw(canvas, projector);
2017         }
2018     }
2019     DisplayOptionChanged();
2020 }
2021
2022 void MLDemos::CanvasMoveEvent()
2023 {
2024     if(canvas->canvasType) return;
2025     drawTimer->Stop();
2026     drawTimer->Clear();
2027     UpdateLearnedModel();
2028
2029     QMutexLocker lock(&mutex);
2030     if(canvas->canvasType)
2031     {
2032         if(classifier)
2033         {
2034             classifiers[tabUsedForTraining]->Draw(canvas, classifier);
2035             if(classifier->UsesDrawTimer())
2036             {
2037                 drawTimer->start(QThread::NormalPriority);
2038             }
2039         }
2040         else if(regressor)
2041         {
2042             regressors[tabUsedForTraining]->Draw(canvas, regressor);
2043             //drawTimer->start(QThread::NormalPriority);
2044         }
2045         else if(clusterer)
2046         {
2047             clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
2048             drawTimer->start(QThread::NormalPriority);
2049         }
2050         else if(dynamical)
2051         {
2052             dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
2053             if(dynamicals[tabUsedForTraining]->UsesDrawTimer()) drawTimer->start(QThread::NormalPriority);
2054         }
2055         else if(projector)
2056         {
2057             projectors[tabUsedForTraining]->Draw(canvas, projector);
2058         }
2059     }
2060     canvas->repaint();
2061 }
2062
2063 void MLDemos::ZoomChanged(float d)
2064 {
2065     displayOptions->spinZoom->setValue(displayOptions->spinZoom->value()+d/4);
2066 }
2067
2068 void MLDemos::CanvasTypeChanged()
2069 {
2070     bool bProjected = canvas->data->bProjected;
2071     int type = ui.canvasTypeCombo->currentIndex();
2072     ui.canvasZoomSlider->setEnabled(false);
2073     ui.canvasZoomSlider->hide();
2074     ui.canvasAxesWidget->hide();
2075     switch(type)
2076     {
2077     case 0: // standard
2078         ui.canvasAxesWidget->show();
2079         ui.canvasX3Spin->setEnabled(false);
2080         ui.canvasX1Label->setText(bProjected ? "e1" : "x1");
2081         ui.canvasX2Label->setText(bProjected ? "e2" : "x2");
2082         break;
2083     case 1: // scatterplot
2084         ui.canvasZoomSlider->show();
2085         ui.canvasZoomSlider->setEnabled(true);
2086         break;
2087     case 2: // parallel coords
2088         break;
2089     case 3: // radial graph (radviz)
2090         break;
2091     case 4: // andrews plots
2092         break;
2093     case 5: // bubble plots
2094         ui.canvasAxesWidget->show();
2095         ui.canvasX3Spin->setEnabled(true);
2096         ui.canvasX1Label->setText(bProjected ? "e1" : "x1");
2097         ui.canvasX2Label->setText(bProjected ? "e2" : "x2");
2098         break;
2099     }
2100     ui.canvasZoomSlider->setEnabled(ui.canvasTypeCombo->currentIndex() == 1);
2101     if(canvas->canvasType == ui.canvasTypeCombo->currentIndex()) return;
2102     canvas->SetCanvasType(ui.canvasTypeCombo->currentIndex());
2103     CanvasOptionsChanged();
2104     UpdateLearnedModel();
2105     canvas->repaint();
2106 }
2107
2108 void MLDemos::CanvasOptionsChanged()
2109 {
2110     float zoom = 1.f + ui.canvasZoomSlider->value()/10.f;
2111     QSizePolicy policy = ui.canvasWidget->sizePolicy();
2112     int dims = canvas ? (canvas->data->GetCount() ? canvas->data->GetSample(0).size() : 2) : 2;
2113     int w = ui.canvasArea->width();
2114     int h = ui.canvasArea->height();
2115     bool bNeedsZoom = false;
2116     if(h/dims < 100)
2117     {
2118         h = 100*dims;
2119         bNeedsZoom = true;
2120     }
2121     if(w/dims < 100)
2122     {
2123         w = 100*dims;
2124         bNeedsZoom = true;
2125     }
2126     //drawTimer->Stop();
2127     //drawTimer->Clear();
2128
2129     if(canvas->canvasType != 1 || (!bNeedsZoom && zoom == 1.f))
2130     {
2131         policy.setHorizontalPolicy(QSizePolicy::Preferred);
2132         policy.setVerticalPolicy(QSizePolicy::Preferred);
2133         ui.canvasWidget->setSizePolicy(policy);
2134         ui.canvasWidget->setMinimumSize(ui.canvasArea->size());
2135         ui.canvasWidget->resize(ui.canvasArea->size());
2136         canvas->resize(ui.canvasWidget->size());
2137         ui.canvasArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2138         ui.canvasArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2139         canvas->SetCanvasType(canvas->canvasType);
2140         canvas->ResizeEvent();
2141
2142         if(mutex.tryLock())
2143         {
2144             if(clusterer)
2145             {
2146                 clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
2147                 drawTimer->start(QThread::NormalPriority);
2148             }
2149             if(dynamical)
2150             {
2151                 dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
2152                 drawTimer->start(QThread::NormalPriority);
2153             }
2154             if(projector)
2155             {
2156                 projectors[tabUsedForTraining]->Draw(canvas, projector);
2157             }
2158             mutex.unlock();
2159         }
2160         return;
2161     }
2162     policy.setHorizontalPolicy(QSizePolicy::Fixed);
2163     policy.setVerticalPolicy(QSizePolicy::Fixed);
2164     ui.canvasWidget->setSizePolicy(policy);
2165     ui.canvasWidget->setMinimumSize(w*zoom,h*zoom);
2166     ui.canvasWidget->resize(w*zoom,h*zoom);
2167     canvas->resize(ui.canvasWidget->size());
2168     ui.canvasArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2169     ui.canvasArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
2170     canvas->SetCanvasType(canvas->canvasType);
2171
2172     if(mutex.tryLock())
2173     {
2174         if(classifier)
2175         {
2176             classifiers[tabUsedForTraining]->Draw(canvas, classifier);
2177         }
2178         else if(regressor)
2179         {
2180             regressors[tabUsedForTraining]->Draw(canvas, regressor);
2181         }
2182         else if(dynamical)
2183         {
2184             dynamicals[tabUsedForTraining]->Draw(canvas, dynamical);
2185             drawTimer->start(QThread::NormalPriority);
2186         }
2187         else if(maximizer)
2188         {
2189         }
2190         if(clusterer)
2191         {
2192             clusterers[tabUsedForTraining]->Draw(canvas, clusterer);
2193             drawTimer->start(QThread::NormalPriority);
2194         }
2195         if(projector)
2196         {
2197             projectors[tabUsedForTraining]->Draw(canvas, projector);
2198         }
2199         mutex.unlock();
2200     }
2201     canvas->ResizeEvent();
2202 }
2203
2204 void MLDemos::Navigation( fvec sample )
2205 {
2206     if(sample[0]==-1)
2207     {
2208         ZoomChanged(sample[1]);
2209         return;
2210     }
2211     QString information;
2212     char string[255];
2213     int count = canvas->data->GetCount();
2214     int pcount = 0, ncount = 0;
2215     ivec labels = canvas->data->GetLabels();
2216     FOR(i, labels.size())
2217     {
2218         if(labels[i] == 0) ++pcount;
2219         else ++ncount;
2220     }
2221     sprintf(string, "samples: %d (o:%.3d|x:%.3d)", count, pcount, ncount);
2222     information += QString(string);
2223     sprintf(string, " | x%d: %.3f x%d: %.3f", canvas->xIndex+1, sample[canvas->xIndex], canvas->yIndex+1, sample[canvas->yIndex]);
2224     information += QString(string);
2225     mutex.tryLock(500);
2226     if(classifier)
2227     {
2228         float score;
2229         if(classifier->IsMultiClass())
2230         {
2231             fvec res = classifier->TestMulti(sample);
2232             int max = 0;
2233             FOR(i, res.size()) if(res[max] < res[i]) max = i;
2234             score = classifier->inverseMap[max];
2235         }
2236         else
2237         {
2238             score = classifier->Test(sample);
2239         }
2240         drawTimer->bPaused = false;
2241         sprintf(string, " | value: %.4f", score);
2242         information += QString(string);
2243     }
2244     else if(dynamical)
2245     {
2246         // we build the trajectory(by hand)
2247
2248         int count = 1000;
2249         std::vector<fvec> trajectory;
2250         fvec position = sample;
2251         if(dynamical->avoid) dynamical->avoid->SetObstacles(canvas->data->GetObstacles());
2252         FOR(i, count)
2253         {
2254             trajectory.push_back(position);
2255             fvec velocity = dynamical->Test(position);
2256             if(dynamical->avoid)
2257             {
2258                 fvec newVelocity = dynamical->avoid->Avoid(position, velocity);
2259                 velocity = newVelocity;
2260             }
2261             position += velocity*dynamical->dT;
2262             if(velocity == 0) break;
2263         }
2264         canvas->liveTrajectory = trajectory;
2265         canvas->repaint();
2266     }
2267     mutex.unlock();
2268     ui.statusBar->showMessage(information);
2269 }
2270
2271 void MLDemos::TargetButton()
2272 {
2273     QDrag *drag = new QDrag(this);
2274     QMimeData *mimeData = new QMimeData;
2275
2276     mimeData->setText("Target");
2277     drag->setMimeData(mimeData);
2278     QPixmap pixmap(33,33);
2279     pixmap.fill();
2280     QPainter painter(&pixmap);
2281     painter.setRenderHint(QPainter::Antialiasing);
2282     painter.setPen(QPen(Qt::black, 1.5));
2283     painter.setBrush(Qt::NoBrush);
2284
2285     int pad = 4, radius = 8;
2286     painter.drawEllipse(QPoint(16,16), radius, radius);
2287     painter.setBrush(Qt::black);
2288     painter.drawLine(QPoint(16,16) - QPoint(radius,radius), QPoint(16,16) - QPoint(radius+pad,radius+pad));
2289     painter.drawLine(QPoint(16,16) + QPoint(radius,radius), QPoint(16,16) + QPoint(radius+pad,radius+pad));
2290     painter.drawLine(QPoint(16,16) - QPoint(radius,-radius), QPoint(16,16) - QPoint(radius+pad,-radius-pad));
2291     painter.drawLine(QPoint(16,16) + QPoint(radius,-radius), QPoint(16,16) + QPoint(radius+pad,-radius-pad));
2292     drag->setPixmap(pixmap);
2293     drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2));
2294
2295     // maximization only allows one target, so we take the others out
2296     if(algorithmOptions->tabMax->isVisible())
2297     {
2298         canvas->targets.clear();
2299         canvas->targetAge.clear();
2300         canvas->repaint();
2301     }
2302     Qt::DropAction dropAction = drag->exec();
2303 }
2304
2305 void MLDemos::ClearTargets()
2306 {
2307     if(!canvas->targets.size()) return;
2308     canvas->targets.clear();
2309     canvas->targetAge.clear();
2310     canvas->maps.animation = QPixmap();
2311     canvas->repaint();
2312 }
2313
2314 void MLDemos::GaussianButton()
2315 {
2316     QDrag *drag = new QDrag(this);
2317     QMimeData *mimeData = new QMimeData;
2318
2319     mimeData->setText("Gaussian");
2320     mimeData->setColorData(QVariant(optionsMaximize->varianceSpin->value()));
2321     drag->setMimeData(mimeData);
2322     QPixmap pixmap(33,33);
2323     pixmap.fill();
2324     QPainter painter(&pixmap);
2325     painter.setRenderHint(QPainter::Antialiasing);
2326     painter.setPen(QPen(Qt::black, 1.5));
2327     painter.setBrush(Qt::NoBrush);
2328     painter.drawEllipse(QPoint(16,16), 12,12);
2329     painter.setBrush(Qt::black);
2330     painter.drawEllipse(QPoint(16,16), 1,1);
2331     drag->setPixmap(pixmap);
2332     drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2));
2333     Qt::DropAction dropAction = drag->exec();
2334 }
2335
2336 void MLDemos::GradientButton()
2337 {
2338     QDrag *drag = new QDrag(this);
2339     QMimeData *mimeData = new QMimeData;
2340
2341     mimeData->setText("Gradient");
2342     drag->setMimeData(mimeData);
2343     QPixmap pixmap(33,33);
2344     pixmap.fill();
2345     QPainter painter(&pixmap);
2346     painter.setRenderHint(QPainter::Antialiasing);
2347     painter.setPen(QPen(Qt::black, 1.5));
2348     painter.setBrush(Qt::NoBrush);
2349     painter.drawLine(QPoint(4,16), QPoint(29,4));
2350     painter.drawLine(QPoint(4,16), QPoint(29,29));
2351     painter.drawLine(QPoint(29,4), QPoint(29,29));
2352     drag->setPixmap(pixmap);
2353     drag->setHotSpot(QPoint(pixmap.width()/2, pixmap.height()/2));
2354     Qt::DropAction dropAction = drag->exec();
2355 }
2356
2357 void MLDemos::BenchmarkButton()
2358 {
2359     int w = canvas->width(), h = canvas->height();
2360     int type = optionsMaximize->benchmarkCombo->currentIndex();
2361     QImage image(w, h, QImage::Format_ARGB32);
2362     image.fill(qRgb(255,255,255));
2363
2364     int dim = 2;
2365     float minSpace = 0.f;
2366     float maxSpace = 1.f;
2367     float minVal = FLT_MAX;
2368     float maxVal = -FLT_MAX;
2369     switch(type)
2370     {
2371     case 0: // griewangk
2372         minSpace = -60.f;
2373         maxSpace = 60.f;
2374         minVal = 0;
2375         maxVal = 2;
2376         break;
2377     case 1: // rastragin
2378         minSpace = -5.12f;
2379         maxSpace = 5.12f;
2380         minVal = 0;
2381         maxVal = 82;
2382         break;
2383     case 2: // schwefel
2384         minSpace = -500.f;
2385         maxSpace = 500.f;
2386         minVal = -838;
2387         maxVal = 838;
2388         break;
2389     case 3: // ackley
2390         minSpace = -2.f;
2391         maxSpace = 2.f;
2392         minVal = 0;
2393         maxVal = 2.3504;
2394     case 4: // michalewicz
2395         minSpace = -2;
2396         maxSpace = 2;
2397         minVal = -1.03159;
2398         maxVal = 5.74;
2399         //              minVal = -1.03159;
2400         //              maxVal = 55.74;
2401     }
2402
2403     bool bSetValues = minVal == FLT_MAX;
2404     Eigen::VectorXd x(2);
2405     fVec point;
2406     float value = 0;
2407     FOR(i, w)
2408     {
2409         x[0] = i/(float)w*(maxSpace - minSpace) + minSpace;
2410         FOR(j, h)
2411         {
2412             x[1] = j/(float)h*(maxSpace - minSpace) + minSpace;
2413
2414             switch(type)
2415             {
2416             case 0:
2417                 value = griewangk(x)(0);
2418                 break;
2419             case 1:
2420                 value = rastragin(x)(0);
2421                 break;
2422             case 2:
2423                 value = schwefel(x)(0);
2424                 break;
2425             case 3:
2426                 value = ackley(x)(0);
2427                 break;
2428             case 4:
2429                 value = sixhump(x)(0);
2430                 break;
2431             }
2432             if(bSetValues)
2433             {
2434                 if(value < minVal) minVal = value;
2435                 if(value > maxVal) maxVal = value;
2436             }
2437             else
2438             {
2439                 value = (value-minVal)/(maxVal-minVal);
2440             }
2441
2442             int color = 255.f*max(0.f,min(1.f,value));
2443             image.setPixel(i,j,qRgba(255, color, color, 255));
2444         }
2445     }
2446     if(bSetValues) qDebug() << "minmax: " << minVal << " " << maxVal;
2447
2448     canvas->maps.reward = QPixmap::fromImage(image);
2449     canvas->repaint();
2450 }
2451
2452 void MLDemos::SaveData()
2453 {
2454     if(!canvas) return;
2455     QString filename = QFileDialog::getSaveFileName(this, tr("Save Data"), "", tr("ML Files (*.ml)"));
2456     if(filename.isEmpty()) return;
2457     if(!filename.endsWith(".ml")) filename += ".ml";
2458     Save(filename);
2459 }
2460 void MLDemos::Save(QString filename)
2461 {
2462     QFile file(filename);
2463     if (!file.open(QIODevice::WriteOnly))
2464     {
2465         ui.statusBar->showMessage("WARNING: Unable to save file");
2466         return;
2467     }
2468     file.close();
2469     canvas->data->Save(filename.toAscii());
2470     if(!canvas->maps.reward.isNull()) canvas->maps.reward.toImage().save(filename + "-reward.png");
2471     SaveParams(filename);
2472     ui.statusBar->showMessage("Data saved successfully");
2473 }
2474
2475 void MLDemos::LoadData()
2476 {
2477     if(!canvas) return;
2478     QString filename = QFileDialog::getOpenFileName(this, tr("Load Data"), "", tr("ML Files (*.ml)"));
2479     if(filename.isEmpty()) return;
2480     if(!filename.endsWith(".ml")) filename += ".ml";
2481     Load(filename);
2482 }
2483
2484 void MLDemos::Load(QString filename)
2485 {
2486     QFile file(filename);
2487     if (!file.open(QIODevice::ReadOnly))
2488     {
2489         ui.statusBar->showMessage("WARNING: Unable to open file");
2490         return;
2491     }
2492     file.close();
2493     ClearData();
2494     canvas->data->Load(filename.toAscii());
2495     LoadParams(filename);
2496     QImage reward(filename + "-reward.png");
2497     if(!reward.isNull()) canvas->maps.reward = QPixmap::fromImage(reward);
2498     ui.statusBar->showMessage("Data loaded successfully");
2499     ResetPositiveClass();
2500     ManualSelectionUpdated();
2501     UpdateInfo();
2502     canvas->repaint();
2503 }
2504
2505 void MLDemos::ImportData()
2506 {
2507     if(!canvas || !import) return;
2508     QString filename = QFileDialog::getOpenFileName(this, tr("Import Data Data"), "", tr("Dataset Files (*.csv *.data *.txt)"));
2509     if(filename.isEmpty()) return;
2510     import->Start();
2511     import->Parse(filename);
2512     import->SendData();
2513 }
2514
2515 void MLDemos::ImportData(QString filename)
2516 {
2517     import->Start();
2518     import->Parse(filename);
2519     import->SendData();
2520     if(import->GetHeaders().size()) canvas->dimNames = import->GetHeaders();
2521     ui.statusBar->showMessage("Data loaded successfully");
2522 }
2523
2524 void MLDemos::dragEnterEvent(QDragEnterEvent *event)
2525 {
2526     QList<QUrl> dragUrl;
2527     if(event->mimeData()->hasUrls())
2528     {
2529         QList<QUrl> urls = event->mimeData()->urls();
2530         QStringList dataType;
2531         dataType << ".ml" << ".csv" << ".data";
2532         for(int i=0; i<urls.size(); i++)
2533         {
2534             QString filename = urls[i].path();
2535             for(int j=0; j < dataType.size(); j++)
2536             {
2537                 if(filename.toLower().endsWith(dataType[j]))
2538                 {
2539                     dragUrl.push_back(urls[i]);
2540                     break;
2541                 }
2542             }
2543         }
2544         if(dragUrl.size())
2545         {
2546             event->acceptProposedAction();
2547         }
2548     }
2549 }
2550
2551 void MLDemos::dropEvent(QDropEvent *event)
2552 {
2553     if(!event->mimeData()->hasUrls()) return;
2554     FOR(i, event->mimeData()->urls().length())
2555     {
2556         QString filename = event->mimeData()->urls()[i].toLocalFile();
2557         qDebug() << "accepted drop file:" << filename;
2558         if(filename.toLower().endsWith(".ml"))
2559         {
2560             ClearData();
2561             canvas->data->Load(filename.toAscii());
2562             LoadParams(filename);
2563             ui.statusBar->showMessage("Data loaded successfully");
2564             ResetPositiveClass();
2565             ManualSelectionUpdated();
2566             UpdateInfo();
2567             canvas->repaint();
2568         }
2569         else if(filename.toLower().endsWith(".csv") || filename.toLower().endsWith(".data"))
2570         {
2571             ClearData();
2572             ImportData(filename);
2573             ResetPositiveClass();
2574             ManualSelectionUpdated();
2575             UpdateInfo();
2576             canvas->repaint();
2577         }
2578     }
2579     event->acceptProposedAction();
2580 }
2581
2582 void MLDemos::ExportSVG()
2583 {
2584     QString filename = QFileDialog::getSaveFileName(this, tr("Save Vector Image"), "", tr("Images (*.svg)"));
2585     if(filename.isEmpty()) return;
2586     if(!filename.endsWith(".svg")) filename += ".svg";
2587
2588     DrawSVG svg(canvas, &mutex);
2589     svg.classifier = classifier;
2590     svg.regressor = regressor;
2591     svg.clusterer = clusterer;
2592     svg.dynamical = dynamical;
2593     svg.maximizer = maximizer;
2594     svg.projector = projector;
2595     if(classifier) svg.drawClass = classifiers[tabUsedForTraining];
2596     if(regressor) svg.drawRegr = regressors[tabUsedForTraining];
2597     if(dynamical) svg.drawDyn = dynamicals[tabUsedForTraining];
2598     if(clusterer) svg.drawClust = clusterers[tabUsedForTraining];
2599     if(projector) svg.drawProj = projectors[tabUsedForTraining];
2600     svg.Write(filename);
2601     ui.statusBar->showMessage("Vector Image saved successfully");
2602 }
2603
2604 void MLDemos::Screenshot()
2605 {
2606     QString filename = QFileDialog::getSaveFileName(this, tr("Save Screenshot"), "", tr("Images (*.png *.jpg)"));
2607     if(filename.isEmpty()) return;
2608     if(!filename.endsWith(".jpg") && !filename.endsWith(".png")) filename += ".png";
2609     if(!canvas->SaveScreenshot(filename)) ui.statusBar->showMessage("WARNING: Unable to save image");
2610     else ui.statusBar->showMessage("Image saved successfully");
2611 }
2612
2613 void MLDemos::CompareScreenshot()
2614 {
2615     if(!canvas || !compare) return;
2616     QClipboard *clipboard = QApplication::clipboard();
2617     QPixmap screenshot = compare->Display().copy();
2618     clipboard->setImage(screenshot.toImage());
2619     //clipboard->setPixmap(screenshot);
2620     clipboard->setText(compare->ToString());
2621 }
2622
2623 void MLDemos::ToClipboard()
2624 {
2625     QPixmap screenshot = canvas->GetScreenshot();
2626     if(screenshot.isNull())
2627     {
2628         ui.statusBar->showMessage("WARNING: Nothing to copy to clipboard");
2629         return;
2630     }
2631     QClipboard *clipboard = QApplication::clipboard();
2632     clipboard->setImage(screenshot.toImage());
2633     clipboard->setPixmap(screenshot);
2634     ui.statusBar->showMessage("Image copied successfully to clipboard");
2635 }
2636
2637 /************************************/
2638 /*                                  */
2639 /*      Input Output functions      */
2640 /*                                  */
2641 /************************************/
2642
2643 void MLDemos::ActivateIO()
2644 {
2645     QList<QAction *> pluginActions = ui.menuInput_Output->actions();
2646     FOR(i, inputoutputs.size())
2647     {
2648         if(i<pluginActions.size() && inputoutputs[i] && pluginActions[i])
2649         {
2650             if(pluginActions[i]->isChecked())
2651             {
2652                 bInputRunning[i] = true;
2653                 inputoutputs[i]->Start();
2654             }
2655             else if(bInputRunning[i])
2656             {
2657                 bInputRunning[i] = false;
2658                 inputoutputs[i]->Stop();
2659             }
2660         }
2661     }
2662 }
2663
2664 void MLDemos::ActivateImport()
2665 {
2666     QList<QAction *> pluginActions = ui.menuInput_Output->actions();
2667     FOR(i, inputoutputs.size())
2668     {
2669         if(i<pluginActions.size() && inputoutputs[i] && pluginActions[i])
2670         {
2671             if(pluginActions[i]->isChecked())
2672             {
2673                 bInputRunning[i] = true;
2674                 inputoutputs[i]->Start();
2675             }
2676             else if(bInputRunning[i])
2677             {
2678                 bInputRunning[i] = false;
2679                 inputoutputs[i]->Stop();
2680             }
2681         }
2682     }
2683 }
2684
2685 void MLDemos::DisactivateIO(QObject *io)
2686 {
2687     if(!io) return;
2688     // first we find the right plugin
2689     int pluginIndex = -1;
2690     FOR(i, inputoutputs.size())
2691     {
2692         if(inputoutputs[i]->object() == io)
2693         {
2694             pluginIndex = i;
2695             break;
2696         }
2697     }
2698     if(pluginIndex == -1)
2699     {
2700         statusBar()->showMessage("Unable to unload plugin: ");
2701         return; // something weird is going on!
2702     }
2703     QList<QAction *> pluginActions = ui.menuInput_Output->actions();
2704     if(pluginIndex < pluginActions.size() && pluginActions[pluginIndex])
2705     {
2706         pluginActions[pluginIndex]->setChecked(false);
2707         if(bInputRunning[pluginIndex]) inputoutputs[pluginIndex]->Stop();
2708         bInputRunning[pluginIndex] = false;
2709     }
2710     pluginActions = ui.menuImport->actions();
2711     if(pluginIndex < pluginActions.size() && pluginActions[pluginIndex])
2712     {
2713         pluginActions[pluginIndex]->setChecked(false);
2714         if(bInputRunning[pluginIndex]) inputoutputs[pluginIndex]->Stop();
2715         bInputRunning[pluginIndex] = false;
2716     }
2717 }
2718
2719 void MLDemos::SetData(std::vector<fvec> samples, ivec labels, std::vector<ipair> trajectories, bool bProjected)
2720 {
2721     sourceData.clear();
2722     sourceLabels.clear();
2723     projectedData.clear();
2724     if(!canvas) return;
2725     canvas->dimNames.clear();
2726     canvas->sampleColors.clear();
2727     canvas->data->Clear();
2728     canvas->data->AddSamples(samples, labels);
2729     canvas->data->bProjected = bProjected;
2730     if(bProjected) ui.status->setText("Projected Data (PCA, etc.)");
2731     else ui.status->setText("Raw Data");
2732     if(trajectories.size())
2733     {
2734         canvas->data->AddSequences(trajectories);
2735     }
2736     FitToData();
2737     ResetPositiveClass();
2738     ManualSelectionUpdated();
2739     CanvasOptionsChanged();
2740     DrawNone();
2741     canvas->ResetSamples();
2742     canvas->repaint();
2743 }
2744
2745 void MLDemos::SetDimensionNames(QStringList headers)
2746 {
2747     //qDebug() << "setting dimension names" << headers;
2748     canvas->dimNames = headers;
2749     ResetPositiveClass();
2750     CanvasOptionsChanged();
2751     canvas->ResetSamples();
2752     canvas->repaint();
2753 }
2754
2755 void MLDemos::SetClassNames(std::map<int,QString> classNames)
2756 {
2757     canvas->classNames = classNames;
2758     ResetPositiveClass();
2759     CanvasOptionsChanged();
2760     canvas->ResetSamples();
2761     canvas->repaint();
2762 }
2763
2764 void MLDemos::SetTimeseries(std::vector<TimeSerie> timeseries)
2765 {
2766     //  qDebug() << "importing " << timeseries.size() << " timeseries";
2767     sourceData.clear();
2768     sourceLabels.clear();
2769     projectedData.clear();
2770     if(!canvas) return;
2771     canvas->dimNames.clear();
2772     canvas->sampleColors.clear();
2773     canvas->data->Clear();
2774     canvas->data->AddTimeSeries(timeseries);
2775     FitToData();
2776     ResetPositiveClass();
2777     ManualSelectionUpdated();
2778     canvas->ResetSamples();
2779     canvas->repaint();
2780     qDebug() << "added " << canvas->data->GetTimeSeries().size() << " timeseries";
2781     //  qDebug() << " dim: " << dim << " count: " << count << " frames: " << frames;
2782
2783     /*
2784  vector<TimeSerie> series = canvas->data->GetTimeSeries();
2785  FOR(i, series.size())
2786  {
2787   FOR(j, series[i].size())
2788   {
2789    qDebug() << i << " " << j << ": " << series[i][j][0];
2790    FOR(d, series[i][j].size())
2791    {
2792 //                              qDebug() << i << " " << j << " " << d << ": " << series[i][j][d];
2793    }
2794   }
2795  }
2796  */
2797 }
2798
2799 void MLDemos::QueryClassifier(std::vector<fvec> samples)
2800 {
2801     std::vector<fvec> results;
2802     QMutexLocker lock(&mutex);
2803     fvec result;
2804     result.resize(1);
2805     if(classifier && samples.size())
2806     {
2807         results.resize(samples.size());
2808         FOR(i, samples.size())
2809         {
2810             result[0] = classifier->Test(samples[i]);
2811             results[i] = result;
2812         }
2813     }
2814     emit SendResults(results);
2815 }
2816
2817 void MLDemos::QueryRegressor(std::vector<fvec> samples)
2818 {
2819     std::vector<fvec> results;
2820     QMutexLocker lock(&mutex);
2821     if(regressor && samples.size())
2822     {
2823         results.resize(samples.size());
2824         FOR(i, samples.size())
2825         {
2826             results[i] = regressor->Test(samples[i]);
2827         }
2828     }
2829     emit SendResults(results);
2830 }
2831
2832 void MLDemos::QueryDynamical(std::vector<fvec> samples)
2833 {
2834     std::vector<fvec> results;
2835     QMutexLocker lock(&mutex);
2836     if(dynamical && samples.size())
2837     {
2838         results.resize(samples.size());
2839         FOR(i, samples.size())
2840         {
2841             results[i] = dynamical->Test(samples[i]);
2842         }
2843     }
2844     emit SendResults(results);
2845 }
2846
2847 void MLDemos::QueryClusterer(std::vector<fvec> samples)
2848 {
2849     std::vector<fvec> results;
2850     QMutexLocker lock(&mutex);
2851     if(clusterer && samples.size())
2852     {
2853         results.resize(samples.size());
2854         FOR(i, samples.size())
2855         {
2856             results[i] = clusterer->Test(samples[i]);
2857         }
2858     }
2859     emit SendResults(results);
2860 }
2861
2862 void MLDemos::QueryMaximizer(std::vector<fvec> samples)
2863 {
2864     std::vector<fvec> results;
2865     QMutexLocker lock(&mutex);
2866     if(maximizer && samples.size())
2867     {
2868         results.resize(samples.size());
2869         FOR(i, samples.size())
2870         {
2871             results[i] = maximizer->Test(samples[i]);
2872         }
2873     }
2874     emit SendResults(results);
2875 }
2876
2877 void MLDemos::QueryProjector(std::vector<fvec> samples)
2878 {
2879     std::vector<fvec> results;
2880     QMutexLocker lock(&mutex);
2881     if(projector && samples.size())
2882     {
2883         results.resize(samples.size());
2884         FOR(i, samples.size())
2885         {
2886             results[i] = projector->Project(samples[i]);
2887         }
2888     }
2889     emit SendResults(results);
2890 }