Merge branch 'devel' of git://gitorious.org/mldemos/mldemos into devel
[mldemos:baraks-mldemos.git] / MLDemos / gridsearch.cpp
1 #include "gridsearch.h"
2 #include <QPixmap>
3 #include <QClipboard>
4 #include <basicMath.h>
5 #include "ui_gridsearch.h"
6
7 using namespace std;
8
9 GridLabel::GridLabel(QWidget *parent)
10     : QLabel(parent)
11 {
12     setMouseTracking(true);
13     setCursor(Qt::CrossCursor);
14 }
15
16 void GridLabel::focusOutEvent(QFocusEvent *ev)
17 {
18     qDebug() << "focus out";
19     emit(MouseMove(new QMouseEvent(QEvent::MouseMove, QPoint(-1,-1),Qt::NoButton,Qt::NoButton,Qt::NoModifier)));
20 }
21
22 void GridLabel::mouseMoveEvent(QMouseEvent *event)
23 {
24     emit(MouseMove(event));
25 }
26
27 GridSearch::GridSearch(Canvas *canvas, QWidget *parent) :
28     QWidget(parent),
29     ui(new Ui::GridSearch),
30     canvas(canvas),
31     mapX(0),mapY(0),
32     classifier(0),
33     clusterer(0),
34     regressor(0),
35     dynamical(0),
36     avoider(0),
37     maximizer(0),
38     reinforcement(0),
39     projector(0)
40 {
41     ui->setupUi(this);
42     connect(ui->closeButton, SIGNAL(clicked()), this, SLOT(Close()));
43     connect(ui->names1Combo, SIGNAL(currentIndexChanged(int)), this, SLOT(OptionsChanged()));
44     connect(ui->names2Combo, SIGNAL(currentIndexChanged(int)), this, SLOT(OptionsChanged()));
45     connect(ui->runButton, SIGNAL(clicked()), this, SLOT(Run()));
46     connect(ui->clipboardButton, SIGNAL(clicked()), this, SLOT(Clipboard()));
47     connect(ui->displayLabel, SIGNAL(MouseMove(QMouseEvent*)), this, SLOT(MouseMove(QMouseEvent*)));
48     connect(ui->colorCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(DisplayChanged()));
49     connect(ui->resultCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(DisplayChanged()));
50     ui->displayLabel->setScaledContents(true);
51     ui->colorbarLabel->setScaledContents(true);
52 }
53
54 GridSearch::~GridSearch()
55 {
56     delete ui;
57 }
58
59 void GridSearch::Clipboard()
60 {
61     QClipboard *clipboard = QApplication::clipboard();
62     QPixmap screenshot = pixmap;
63     if(screenshot.isNull()) return;
64     clipboard->setImage(screenshot.toImage());
65     clipboard->setPixmap(screenshot);
66 }
67
68 void GridSearch::DisplayChanged()
69 {
70     DisplayResults();
71     repaint();
72 }
73
74 ivec toBinary(ivec labels)
75 {
76     ivec newLabels(labels.size(), 1);
77     map<int,int> class2labels;
78     int cnt=0;
79     FOR(i, labels.size())
80     {
81         if(!class2labels.count(labels[i])) class2labels[labels[i]] = cnt++;
82     }
83     if(class2labels.size() == 1) return newLabels;
84     if(class2labels.count(0)) // we have a negative class!
85     {
86         FOR(i, labels.size()) if(labels[i] == 0) newLabels[i] = -1;
87     }
88     else // we pick the first one as the positive class
89     {
90         if(class2labels.count(1)) // we have a positive class!
91         {
92             FOR(i, labels.size()) if(labels[i] != 1) newLabels[i] = -1;
93         }
94         else
95         {
96             int posClass = labels[0];
97             FOR(i, labels.size()) if(labels[i] != posClass) newLabels[i] = -1;
98         }
99     }
100     return newLabels;
101 }
102
103 void GridSearch::MouseMove(QMouseEvent *event)
104 {
105     mousePoint = QPoint(event->x(), event->y());
106     if(map.size())
107     {
108         /*
109         int x = event->x() * mapX / pixmap.width();
110         int y = event->y() * mapY / pixmap.height();
111         float value = map[x + y * mapX];
112         qDebug() << "value" << x << y << value;
113         */
114         repaint();
115     }
116 }
117
118 void GridSearch::Close()
119 {
120     this->hide();
121 }
122
123 void GridSearch::paintEvent(QPaintEvent *event)
124 {
125     QWidget::paintEvent(event);
126
127     if(pixmap.isNull()) return;
128     if(mousePoint.x() == -1 && mousePoint.y() == -1)
129     {
130         ui->displayLabel->setPixmap(pixmap);
131         return;
132     }
133     int W = pixmap.width();
134     int H = pixmap.height();
135     int x = mousePoint.x() * mapX / W;
136     int y = mousePoint.y() * mapY / H;
137     int pX = (x+0.5)*W/mapX;
138     int pY = (y+0.5)*H/mapY;
139     int rW = 100;
140     int rH = 40;
141     int rX = pX + 5;
142     int rY = pY + 5;
143     if(rX + rW > W) rX = pX - rW - 5;
144     if(rY + rH > H) rY = pY - rH - 5;
145
146     int index1 = ui->names1Combo->currentIndex();
147     int index2 = ui->names2Combo->currentIndex();
148     QString name1 = index1 < names.size() ? names[index1] : "none";
149     QString name2 = index2 < names.size() ? names[index2] : "none";
150     fPair ranges = GetParamsRange();
151     float param1 = index1 < names.size() ? (x/(float)(mapX-1))*(ranges.first.second - ranges.first.first) + ranges.first.first : 0;
152     float param2 = index2 < names.size() ? (y/(float)(mapY-1))*(ranges.second.second - ranges.second.first) + ranges.second.first : 0;
153     float value = map.size() && mapX && mapY ? map[x+y*mapX] : 0;
154     QString displayString;
155     if(index1 < names.size())
156     {
157         if(types[index1] == "List") displayString += QString("%1:%2\n").arg(name1).arg(values[index1][x]);
158         else displayString += QString("%1:%2\n").arg(name1).arg(param1);
159     }
160     else displayString += QString("None\n");
161     if(index2 < names.size())
162     {
163         if(types[index2] == "List") displayString += QString("%1:%2\n").arg(name2).arg(values[index2][y]);
164         else displayString += QString("%1:%2\n").arg(name2).arg(param2);
165     }
166     else displayString += QString("None\n");
167     displayString += QString("%1: %2").arg(ui->resultCombo->currentText()).arg(value, 0, 'f', 4);
168
169     QPixmap newPixmap = pixmap;
170     QPainter painter(&newPixmap);
171     painter.setRenderHint(QPainter::Antialiasing);
172     painter.setOpacity(0.6);
173     painter.setPen(Qt::NoPen);
174     painter.setBrush(Qt::white);
175     painter.drawRect(rX-2, rY-2, rW+4, rH+4);
176     painter.setOpacity(1);
177     painter.setBrush(Qt::NoBrush);
178     painter.setPen(QPen(Qt::white, 1));
179     painter.drawRect(rX-2, rY-2, rW+4, rH+4);
180     painter.setPen(QPen(Qt::white, 3));
181     painter.drawEllipse(QPoint(pX, pY), 3, 3);
182     painter.setPen(QPen(Qt::black, 1));
183     QFont font = painter.font();
184     font.setPointSize(9);
185     painter.setFont(font);
186     painter.drawText(rX, rY, rW, rH, Qt::AlignVCenter|Qt::AlignLeft,displayString);
187     ui->displayLabel->setPixmap(newPixmap);
188 }
189
190 void GridSearch::DisplayResults()
191 {
192     int colorScheme = ui->colorCombo->currentIndex();
193     int index = ui->resultCombo->currentIndex();
194     if(index == -1) return;
195     map = mapList[ui->resultCombo->currentText()];
196
197     float minVal = FLT_MAX, maxVal = -FLT_MAX;
198     FOR(i, map.size())
199     {
200         minVal = min(minVal, map[i]);
201         maxVal = max(maxVal, map[i]);
202     }
203     if(minVal == maxVal)
204     {
205         minVal = 0;
206         maxVal = 1;
207     }
208
209     int xSteps = mapX;
210     int ySteps = mapY;
211     QImage tinyMap(xSteps, ySteps, QImage::Format_RGB32);
212     FOR(y, ySteps)
213     {
214         FOR(x, xSteps)
215         {
216             float v = (map[x+y*xSteps]-minVal)/(maxVal-minVal);
217             QRgb color = Canvas::GetColorMapValue(v, colorScheme);
218             tinyMap.setPixel(x,y,color);
219         }
220     }
221     int W = ui->displayLabel->width();
222     int H = ui->displayLabel->height();
223
224     pixmap = QPixmap::fromImage(tinyMap.scaled(W,H,Qt::IgnoreAspectRatio, Qt::FastTransformation));
225     QPainter painter(&pixmap);
226     painter.setPen(QPen(Qt::black, 0.5f));
227     FOR(y, ySteps+1)
228     {
229         int h = y*pixmap.height()/(ySteps);
230         if(y == ySteps) h = pixmap.height()-1;
231         painter.drawLine(0,h, pixmap.width(), h);
232     }
233     FOR(x, xSteps+1)
234     {
235         int w = x*pixmap.width()/(xSteps);
236         if(x == xSteps) w = pixmap.width()-1;
237         painter.drawLine(w, 0, w, pixmap.height());
238     }
239     ui->displayLabel->setPixmap(pixmap);
240     ui->displayLabel->repaint();
241
242     int cW = ui->colorbarLabel->width();
243     int cH = ui->colorbarLabel->height();
244     int cpad = 6;
245     QPixmap colorBar(cW,cH);
246     QBitmap bitmap(cW,cH);
247     colorBar.setMask(bitmap);
248     colorBar.fill(Qt::transparent);
249     QPainter painterBar(&colorBar);
250     painterBar.setBrush(Qt::NoBrush);
251     FOR(i, cH-cpad*2)
252     {
253         float v = i/(float)(cH-cpad*2);
254         QRgb color = Canvas::GetColorMapValue(v, colorScheme);
255         painterBar.setPen(color);
256         painterBar.drawLine(0,cH-cpad-i,20,cH-cpad-i);
257     }
258     ySteps = 10;
259     QFont font = painterBar.font();
260     font.setPointSize(7);
261     painterBar.setFont(font);
262     painterBar.setPen(Qt::black);
263     FOR(i, ySteps+1)
264     {
265         float y = (1.f-i/(float)ySteps)*(cH-cpad*2) + cpad;
266         float v = i/(float)ySteps*(maxVal-minVal) + minVal;
267         painterBar.drawLine(0,y,2,y);
268         painterBar.drawLine(18,y,20,y);
269         painterBar.drawText(22,y+3, QString("%1").arg(v,0,'f',2));
270     }
271     painterBar.drawRect(0,cpad,20,cH-cpad*2);
272
273     ui->colorbarLabel->setPixmap(colorBar);
274     ui->colorbarLabel->repaint();
275
276 }
277
278 fPair GridSearch::GetParamsRange()
279 {
280     int xSteps = ui->steps1Spin->value();
281     int ySteps = ui->steps2Spin->value();
282     int xIndex = ui->names1Combo->currentIndex();
283     int yIndex = ui->names2Combo->currentIndex();
284     bool bNone1 = xIndex == ui->names1Combo->count()-1;
285     bool bNone2 = yIndex == ui->names2Combo->count()-1;
286     float xMin=0, xMax=0, yMin=0, yMax=0;
287     if(bNone1) xSteps = 1; // none!
288     else
289     {
290         if(types[xIndex] == "List")
291         {
292             xMin = 0; xMax = values[xIndex].size();
293         }
294         else
295         {
296             xMin = ui->start1Spin->value();
297             xMax = ui->stop1Spin->value();
298         }
299         if(types[xIndex] == "Integer") xSteps = min(xSteps, (int)(xMax-xMin)+1);
300     }
301     if(bNone2) ySteps = 1; // none!
302     else
303     {
304         if(types[yIndex] == "List")
305         {
306             yMin = 0; yMax = values[yIndex].size();
307         }
308         else
309         {
310             yMin = ui->start2Spin->value();
311             yMax = ui->stop2Spin->value();
312         }
313         if(types[yIndex] == "Integer") ySteps = min(ySteps, (int)(yMax-yMin)+1);
314     }
315     if(xMin==xMax) xSteps = 1;
316     if(yMin==yMax) ySteps = 1;
317     fPair ranges;
318     ranges.first = make_pair(xMin,xMax);
319     ranges.second = make_pair(yMin,yMax);
320     return ranges;
321 }
322
323 void GridSearch::Run()
324 {
325     mapList.clear();
326     int xSteps = ui->steps1Spin->value();
327     int ySteps = ui->steps2Spin->value();
328     int xIndex = ui->names1Combo->currentIndex();
329     int yIndex = ui->names2Combo->currentIndex();
330     bool bNone1 = xIndex == ui->names1Combo->count()-1;
331     bool bNone2 = yIndex == ui->names2Combo->count()-1;
332     if(bNone1 && bNone2) return;
333     float xMin=0, xMax=0, yMin=0, yMax=0;
334     if(bNone1) xSteps = 1; // none!
335     else
336     {
337         if(types[xIndex] == "List")
338         {
339             xMin = 0; xMax = values[xIndex].size();
340         }
341         else
342         {
343             xMin = ui->start1Spin->value();
344             xMax = ui->stop1Spin->value();
345         }
346         if(types[xIndex] == "Integer") xSteps = min(xSteps, (int)(xMax-xMin)+1);
347     }
348     if(bNone2) ySteps = 1; // none!
349     else
350     {
351         if(types[yIndex] == "List")
352         {
353             yMin = 0; yMax = values[yIndex].size();
354         }
355         else
356         {
357             yMin = ui->start2Spin->value();
358             yMax = ui->stop2Spin->value();
359         }
360         if(types[yIndex] == "Integer") ySteps = min(ySteps, (int)(yMax-yMin)+1);
361     }
362     if(xMin==xMax) xSteps = 1;
363     if(yMin==yMax) ySteps = 1;
364     int folds = ui->foldSpin->value();
365     fvec oldParams;
366     if(classifier) oldParams = classifier->GetParams();
367     if(clusterer) oldParams = clusterer->GetParams();
368     if(regressor) oldParams = regressor->GetParams();
369     if(dynamical) oldParams = dynamical->GetParams();
370     if(avoider) oldParams = avoider->GetParams();
371     if(maximizer) oldParams = maximizer->GetParams();
372     fvec params = oldParams;
373     float trainRatio = 0.66;
374     vector<fvec> samples = canvas->data->GetSamples();
375     ivec labels = canvas->data->GetLabels();
376     ivec binLabels = toBinary(labels);
377     ui->progressBar->setValue(0);
378     ui->progressBar->setMaximum(xSteps*ySteps);
379     fvec errorMap(xSteps*ySteps);
380     fvec fmeasureMap(xSteps*ySteps);
381     FOR(y, ySteps)
382     {
383         FOR(x, xSteps)
384         {
385             if(!bNone1) params[xIndex] = x / (float) (xSteps-1) * (xMax - xMin) + xMin;
386             if(!bNone2) params[yIndex] = y / (float) (ySteps-1) * (yMax - yMin) + yMin;
387             int trainCount = (int)(trainRatio * samples.size());
388             u32 *perm = randPerm(samples.size());
389             vector<fvec> trainSamples(trainCount);
390             ivec trainLabels(trainCount);
391             ivec trainBinLabels(trainCount);
392             vector<fvec> testSamples(samples.size()-trainCount);
393             ivec testLabels(samples.size()-trainCount);
394             ivec testBinLabels(samples.size()-trainCount);
395             fvec measure1(folds, 0);
396             fvec measure2(folds, 0);
397             FOR(f, folds)
398             {
399                 int foldOffset = (f*samples.size()/folds);
400                 FOR(i, samples.size())
401                 {
402                     if(i < trainCount)
403                     {
404                         trainSamples[i] = samples[perm[(foldOffset + i) % samples.size()]];
405                         trainLabels[i] = labels[perm[(foldOffset + i) % labels.size()]];
406                         trainBinLabels[i] = binLabels[perm[(foldOffset + i) % labels.size()]];
407                     }
408                     else
409                     {
410                         testSamples[i-trainCount] = samples[perm[(foldOffset + i) % samples.size()]];
411                         testLabels[i-trainCount] = labels[perm[(foldOffset + i) % labels.size()]];
412                         testBinLabels[i-trainCount] = binLabels[perm[(foldOffset + i) % labels.size()]];
413                     }
414                 }
415
416                 if(classifier)
417                 {
418                     if(!samples.size()) return;
419                     Classifier *c = classifier->GetClassifier();
420                     classifier->SetParams(c, params);
421                     if(c->IsMultiClass()) c->Train(trainSamples, trainLabels);
422                     else c->Train(trainSamples, trainBinLabels);
423                     float error=0, invError=0;
424                     bool bBinary = false;
425                     rocData rocdata;
426                     FOR(i, testSamples.size())
427                     {
428                         if(c->IsMultiClass())
429                         {
430                             fvec res = c->TestMulti(testSamples[i]);
431                             if(res.size() == 1)
432                             {
433                                 bBinary = true;
434                                 // we use invError because we don't know in which order the classifier
435                                 // has learned the classes, and which has become the de facto positive class
436                                 if(res[0] * testBinLabels[i] < 0) error += 1.f;
437                                 else invError += 1.f;
438                                 rocdata.push_back(f32pair(res[0], (testBinLabels[i]+1)/2));
439                             }
440                             else
441                             {
442
443                                 int winner = 0;
444                                 float score = res[0];
445                                 FOR(j, res.size())
446                                 {
447                                     if(res[j] > score)
448                                     {
449                                         score = res[j];
450                                         winner = j;
451                                     }
452                                 }
453                                 if(winner != testLabels[i]) error += 1.f;
454                                 rocdata.push_back(f32pair(winner, testLabels[i]));
455                             }
456                         }
457                         else
458                         {
459                             bBinary = true;
460                             float res = c->Test(testSamples[i]);
461                             if(res * testBinLabels[i] < 0) error += 1.f;
462                             else invError += 1.f;
463                             rocdata.push_back(f32pair(res, (testBinLabels[i]+1)/2));
464                         }
465                     }
466                     rocdata = FixRocData(rocdata);
467                     if(bBinary) error = min(error, invError);
468                     error /= testSamples.size();
469                     measure1[f] = error;
470                     // we use micro f-measure for multi-class
471                     float eff = bBinary ? GetRocValueAt(rocdata, 0) : GetMicroMacroFMeasure(rocdata).first;
472                     measure2[f] = eff;
473                     DEL(c);
474                 }
475                 else if(clusterer);
476                 else if(regressor)
477                 {
478                     if(!samples.size()) return;
479                     Regressor *r = regressor->GetRegressor();
480                     regressor->SetParams(r, params);
481                     int outputDim = samples[0].size()-1;
482                     r->SetOutputDim(outputDim);
483                     r->Train(trainSamples, trainLabels);
484                     float error = 0;
485                     FOR(i, testSamples.size())
486                     {
487                         fvec res = r->Test(testSamples[i]);
488                         // we compute the mse
489                         error += sqrtf((res[0] - trainSamples[i][outputDim])*(res[0] - trainSamples[i][outputDim]));
490                     }
491                     error /= testSamples.size();
492                     measure1[f] = error;
493                 }
494                 else if(dynamical);
495                 else if(avoider);
496                 else if(maximizer);
497                 else if(reinforcement);
498                 else if(projector);
499             }
500             KILL(perm);
501             // now we fill the error map
502             float mean = 0, effMean = 0;
503             FOR(f, folds)
504             {
505                 mean += measure1[f];
506                 effMean += measure2[f];
507             }
508             mean /= folds;
509             effMean /= folds;
510             qDebug() << "mean" << mean << "fmeasure" << effMean;
511             errorMap[x+y*xSteps] = mean;
512             fmeasureMap[x+y*xSteps] = effMean;
513             ui->progressBar->setValue(x+y*xSteps);
514             ui->progressBar->repaint();
515             qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
516         }
517     }
518     if(classifier)
519     {
520         mapList["Error"] = errorMap;
521         mapList["FMeasure"] = fmeasureMap;
522         map = errorMap;
523     }
524     else if(regressor)
525     {
526         mapList["Error"] = errorMap;
527     }
528     bool bSig = ui->resultCombo->blockSignals(true);
529     ui->resultCombo->clear();
530     for(std::map<QString,fvec>::iterator it = mapList.begin(); it != mapList.end(); it++)
531     {
532         ui->resultCombo->addItem(it->first);
533     }
534     ui->resultCombo->setCurrentIndex(0);
535     ui->resultCombo->blockSignals(bSig);
536     mapX = xSteps;
537     mapY = ySteps;
538     DisplayResults();
539     ui->progressBar->setValue(0);
540     repaint();
541 }
542
543 void GridSearch::OptionsChanged()
544 {
545     int index1 = ui->names1Combo->currentIndex();
546     int index2 = ui->names2Combo->currentIndex();
547     if(index1 < types.size())
548     {
549         bool bList = types[index1] == "List";
550         ui->start1Spin->setEnabled(!bList);
551         ui->stop1Spin->setEnabled(!bList);
552         ui->steps1Spin->setEnabled(!bList);
553         float start=0, stop=99999;
554         if(!bList)
555         {
556             if(values[index1].size() > 0) start = values[index1][0].toFloat();
557             if(values[index1].size() > 1) stop = values[index1][1].toFloat();
558             if(ui->start1Spin->value() < start) ui->start1Spin->setValue(start);
559             if(ui->stop1Spin->value() < ui->start1Spin->value()) ui->stop1Spin->setValue(ui->start1Spin->value()+1);
560             if(ui->stop1Spin->value() > stop) ui->stop1Spin->setValue(stop);
561             ui->steps1Spin->setValue(10);
562             if(types[index1] == "Integer")
563             {
564                 ui->start1Spin->setSingleStep(1);
565                 ui->stop1Spin->setSingleStep(1);
566                 ui->start1Spin->setDecimals(0);
567                 ui->stop1Spin->setDecimals(0);
568             }
569             else if(types[index1] == "Real")
570             {
571                 ui->start1Spin->setSingleStep((stop-start)*0.001);
572                 ui->stop1Spin->setSingleStep((stop-start)*0.001);
573                 ui->start1Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
574                 ui->stop1Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
575             }
576         }
577         else ui->steps1Spin->setValue(values[index1].size());
578     }
579     else
580     {
581         ui->start1Spin->setEnabled(false);
582         ui->stop1Spin->setEnabled(false);
583         ui->steps1Spin->setEnabled(false);
584     }
585     if(index2 < types.size())
586     {
587         bool bList = types[index2] == "List";
588         ui->start2Spin->setEnabled(!bList);
589         ui->stop2Spin->setEnabled(!bList);
590         ui->steps2Spin->setEnabled(!bList);
591         float start=0, stop=99999;
592         if(!bList)
593         {
594             if(values[index2].size() > 0) start = values[index2][0].toFloat();
595             if(values[index2].size() > 1) stop = values[index2][1].toFloat();
596             if(ui->start2Spin->value() < start) ui->start2Spin->setValue(start);
597             if(ui->stop2Spin->value() < ui->start2Spin->value()) ui->stop2Spin->setValue(ui->start2Spin->value()+1);
598             if(ui->stop2Spin->value() > stop) ui->stop2Spin->setValue(stop);
599             ui->steps2Spin->setValue(10);
600             if(types[index2] == "Integer")
601             {
602                 ui->start2Spin->setSingleStep(1);
603                 ui->stop2Spin->setSingleStep(1);
604             }
605             else if(types[index2] == "Real")
606             {
607                 ui->start2Spin->setSingleStep((stop-start)*0.001);
608                 ui->stop2Spin->setSingleStep((stop-start)*0.001);
609                 ui->start2Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
610                 ui->stop2Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
611             }
612         }
613         else ui->steps2Spin->setValue(values[index2].size());
614     }
615     else
616     {
617         ui->start2Spin->setEnabled(false);
618         ui->stop2Spin->setEnabled(false);
619         ui->steps2Spin->setEnabled(false);
620     }
621 }
622
623 void GridSearch::Update()
624 {
625     names.clear();
626     types.clear();
627     values.clear();
628     if(classifier)
629         classifier->GetParameterList(names, types, values);
630     if(clusterer)
631         clusterer->GetParameterList(names, types, values);
632     if(regressor)
633         regressor->GetParameterList(names, types, values);
634     if(dynamical)
635         dynamical->GetParameterList(names, types, values);
636     if(avoider)
637         avoider->GetParameterList(names, types, values);
638     if(maximizer)
639         maximizer->GetParameterList(names, types, values);
640     if(reinforcement)
641         reinforcement->GetParameterList(names, types, values);
642     if(projector)
643         projector->GetParameterList(names, types, values);
644     ui->names1Combo->clear();
645     ui->names2Combo->clear();
646     FOR(i, names.size())
647     {
648         ui->names1Combo->addItem(names[i]);
649         ui->names2Combo->addItem(names[i]);
650     }
651     ui->names1Combo->addItem("None");
652     ui->names2Combo->addItem("None");
653     if(names.size() > 0) ui->names1Combo->setCurrentIndex(0);
654     if(names.size() > 1) ui->names2Combo->setCurrentIndex(1);
655 }
656
657 void GridSearch::SetClassifier(ClassifierInterface *c)
658 {
659     if(classifier == c) return;
660     classifier = c;
661     clusterer = 0;
662     regressor = 0;
663     dynamical = 0;
664     avoider = 0;
665     maximizer = 0;
666     reinforcement = 0;
667     projector = 0;
668     pixmap = QPixmap();
669     mousePoint = QPoint(-1,-1);
670     Update();
671 }
672
673 void GridSearch::SetClusterer(ClustererInterface *c)
674 {
675     if(clusterer == c) return;
676     classifier = 0;
677     clusterer = c;
678     regressor = 0;
679     dynamical = 0;
680     avoider = 0;
681     maximizer = 0;
682     reinforcement = 0;
683     projector = 0;
684     pixmap = QPixmap();
685     mousePoint = QPoint(-1,-1);
686     Update();
687 }
688
689 void GridSearch::SetRegressor(RegressorInterface *c)
690 {
691     if(regressor == c) return;
692     classifier = 0;
693     clusterer = 0;
694     regressor = c;
695     dynamical = 0;
696     avoider = 0;
697     maximizer = 0;
698     reinforcement = 0;
699     projector = 0;
700     pixmap = QPixmap();
701     mousePoint = QPoint(-1,-1);
702     Update();
703 }
704
705 void GridSearch::SetDynamical(DynamicalInterface *c)
706 {
707     if(dynamical == c) return;
708     classifier = 0;
709     clusterer = 0;
710     regressor = 0;
711     dynamical = c;
712     avoider = 0;
713     maximizer = 0;
714     reinforcement = 0;
715     projector = 0;
716     pixmap = QPixmap();
717     mousePoint = QPoint(-1,-1);
718     Update();
719 }
720
721 void GridSearch::SetAvoidance(AvoidanceInterface *c)
722 {
723     if(avoider == c) return;
724     classifier = 0;
725     clusterer = 0;
726     regressor = 0;
727     dynamical = 0;
728     avoider = c;
729     maximizer = 0;
730     reinforcement = 0;
731     projector = 0;
732     pixmap = QPixmap();
733     mousePoint = QPoint(-1,-1);
734     Update();
735 }
736
737 void GridSearch::SetMaximizer(MaximizeInterface *c)
738 {
739     if(maximizer == c) return;
740     classifier = 0;
741     clusterer = 0;
742     regressor = 0;
743     dynamical = 0;
744     avoider = 0;
745     maximizer = c;
746     reinforcement = 0;
747     projector = 0;
748     pixmap = QPixmap();
749     mousePoint = QPoint(-1,-1);
750     Update();
751 }
752
753 void GridSearch::SetReinforcement(ReinforcementInterface *c)
754 {
755     if(reinforcement == c) return;
756     classifier = 0;
757     clusterer = 0;
758     regressor = 0;
759     dynamical = 0;
760     avoider = 0;
761     maximizer = 0;
762     reinforcement = c;
763     projector = 0;
764     pixmap = QPixmap();
765     mousePoint = QPoint(-1,-1);
766     Update();
767 }
768
769 void GridSearch::SetProjector(ProjectorInterface *c)
770 {
771     if(projector == c) return;
772     classifier = 0;
773     clusterer = 0;
774     regressor = 0;
775     dynamical = 0;
776     avoider = 0;
777     maximizer = 0;
778     reinforcement = 0;
779     projector = c;
780     pixmap = QPixmap();
781     mousePoint = QPoint(-1,-1);
782     Update();
783 }