Merge remote-tracking branch 'upstream/devel' 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     //bitmap.clea();
248     //colorBar.setMask(bitmap);
249     colorBar.fill(Qt::transparent);
250     QPainter painterBar(&colorBar);
251     painterBar.setBrush(Qt::NoBrush);
252     FOR(i, cH-cpad*2)
253     {
254         float v = i/(float)(cH-cpad*2);
255         QRgb color = Canvas::GetColorMapValue(v, colorScheme);
256         painterBar.setPen(color);
257         painterBar.drawLine(0,cH-cpad-i,20,cH-cpad-i);
258     }
259     ySteps = 10;
260     QFont font = painterBar.font();
261     font.setPointSize(7);
262     painterBar.setFont(font);
263     painterBar.setPen(Qt::black);
264     FOR(i, ySteps+1)
265     {
266         float y = (1.f-i/(float)ySteps)*(cH-cpad*2) + cpad;
267         float v = i/(float)ySteps*(maxVal-minVal) + minVal;
268         painterBar.drawLine(0,y,2,y);
269         painterBar.drawLine(18,y,20,y);
270         painterBar.drawText(22,y+3, QString("%1").arg(v,0,'f',2));
271     }
272     painterBar.drawRect(0,cpad,20,cH-cpad*2);
273
274     ui->colorbarLabel->setPixmap(colorBar);
275     ui->colorbarLabel->repaint();
276
277 }
278
279 fPair GridSearch::GetParamsRange()
280 {
281     int xSteps = ui->steps1Spin->value();
282     int ySteps = ui->steps2Spin->value();
283     int xIndex = ui->names1Combo->currentIndex();
284     int yIndex = ui->names2Combo->currentIndex();
285     bool bNone1 = xIndex == ui->names1Combo->count()-1;
286     bool bNone2 = yIndex == ui->names2Combo->count()-1;
287     float xMin=0, xMax=0, yMin=0, yMax=0;
288     if(bNone1) xSteps = 1; // none!
289     else
290     {
291         if(types[xIndex] == "List")
292         {
293             xMin = 0; xMax = values[xIndex].size();
294         }
295         else
296         {
297             xMin = ui->start1Spin->value();
298             xMax = ui->stop1Spin->value();
299         }
300         if(types[xIndex] == "Integer") xSteps = min(xSteps, (int)(xMax-xMin)+1);
301     }
302     if(bNone2) ySteps = 1; // none!
303     else
304     {
305         if(types[yIndex] == "List")
306         {
307             yMin = 0; yMax = values[yIndex].size();
308         }
309         else
310         {
311             yMin = ui->start2Spin->value();
312             yMax = ui->stop2Spin->value();
313         }
314         if(types[yIndex] == "Integer") ySteps = min(ySteps, (int)(yMax-yMin)+1);
315     }
316     if(xMin==xMax) xSteps = 1;
317     if(yMin==yMax) ySteps = 1;
318     fPair ranges;
319     ranges.first = make_pair(xMin,xMax);
320     ranges.second = make_pair(yMin,yMax);
321     return ranges;
322 }
323
324 void GridSearch::Run()
325 {
326     mapList.clear();
327     int xSteps = ui->steps1Spin->value();
328     int ySteps = ui->steps2Spin->value();
329     int xIndex = ui->names1Combo->currentIndex();
330     int yIndex = ui->names2Combo->currentIndex();
331     bool bNone1 = xIndex == ui->names1Combo->count()-1;
332     bool bNone2 = yIndex == ui->names2Combo->count()-1;
333     if(bNone1 && bNone2) return;
334     float xMin=0, xMax=0, yMin=0, yMax=0;
335     if(bNone1) xSteps = 1; // none!
336     else
337     {
338         if(types[xIndex] == "List")
339         {
340             xMin = 0; xMax = values[xIndex].size();
341         }
342         else
343         {
344             xMin = ui->start1Spin->value();
345             xMax = ui->stop1Spin->value();
346         }
347         if(types[xIndex] == "Integer") xSteps = min(xSteps, (int)(xMax-xMin)+1);
348     }
349     if(bNone2) ySteps = 1; // none!
350     else
351     {
352         if(types[yIndex] == "List")
353         {
354             yMin = 0; yMax = values[yIndex].size();
355         }
356         else
357         {
358             yMin = ui->start2Spin->value();
359             yMax = ui->stop2Spin->value();
360         }
361         if(types[yIndex] == "Integer") ySteps = min(ySteps, (int)(yMax-yMin)+1);
362     }
363     if(xMin==xMax) xSteps = 1;
364     if(yMin==yMax) ySteps = 1;
365     int folds = ui->foldSpin->value();
366     fvec oldParams;
367     if(classifier) oldParams = classifier->GetParams();
368     if(clusterer) oldParams = clusterer->GetParams();
369     if(regressor) oldParams = regressor->GetParams();
370     if(dynamical) oldParams = dynamical->GetParams();
371     if(avoider) oldParams = avoider->GetParams();
372     if(maximizer) oldParams = maximizer->GetParams();
373     fvec params = oldParams;
374     float trainRatio = 0.66;
375     vector<fvec> samples = canvas->data->GetSamples();
376     ivec labels = canvas->data->GetLabels();
377     ivec binLabels = toBinary(labels);
378     ui->progressBar->setValue(0);
379     ui->progressBar->setMaximum(xSteps*ySteps);
380     fvec errorMap(xSteps*ySteps);
381     fvec fmeasureMap(xSteps*ySteps);
382     FOR(y, ySteps)
383     {
384         FOR(x, xSteps)
385         {
386             if(!bNone1) params[xIndex] = x / (float) (xSteps-1) * (xMax - xMin) + xMin;
387             if(!bNone2) params[yIndex] = y / (float) (ySteps-1) * (yMax - yMin) + yMin;
388             int trainCount = (int)(trainRatio * samples.size());
389             u32 *perm = randPerm(samples.size());
390             vector<fvec> trainSamples(trainCount);
391             ivec trainLabels(trainCount);
392             ivec trainBinLabels(trainCount);
393             vector<fvec> testSamples(samples.size()-trainCount);
394             ivec testLabels(samples.size()-trainCount);
395             ivec testBinLabels(samples.size()-trainCount);
396             fvec measure1(folds, 0);
397             fvec measure2(folds, 0);
398             FOR(f, folds)
399             {
400                 int foldOffset = (f*samples.size()/folds);
401                 FOR(i, samples.size())
402                 {
403                     if(i < trainCount)
404                     {
405                         trainSamples[i] = samples[perm[(foldOffset + i) % samples.size()]];
406                         trainLabels[i] = labels[perm[(foldOffset + i) % labels.size()]];
407                         trainBinLabels[i] = binLabels[perm[(foldOffset + i) % labels.size()]];
408                     }
409                     else
410                     {
411                         testSamples[i-trainCount] = samples[perm[(foldOffset + i) % samples.size()]];
412                         testLabels[i-trainCount] = labels[perm[(foldOffset + i) % labels.size()]];
413                         testBinLabels[i-trainCount] = binLabels[perm[(foldOffset + i) % labels.size()]];
414                     }
415                 }
416
417                 if(classifier)
418                 {
419                     if(!samples.size()) return;
420                     Classifier *c = classifier->GetClassifier();
421                     classifier->SetParams(c, params);
422                     if(c->IsMultiClass()) c->Train(trainSamples, trainLabels);
423                     else c->Train(trainSamples, trainBinLabels);
424                     float error=0, invError=0;
425                     bool bBinary = false;
426                     rocData rocdata;
427                     FOR(i, testSamples.size())
428                     {
429                         if(c->IsMultiClass())
430                         {
431                             fvec res = c->TestMulti(testSamples[i]);
432                             if(res.size() == 1)
433                             {
434                                 bBinary = true;
435                                 // we use invError because we don't know in which order the classifier
436                                 // has learned the classes, and which has become the de facto positive class
437                                 if(res[0] * testBinLabels[i] < 0) error += 1.f;
438                                 else invError += 1.f;
439                                 rocdata.push_back(f32pair(res[0], (testBinLabels[i]+1)/2));
440                             }
441                             else
442                             {
443
444                                 int winner = 0;
445                                 float score = res[0];
446                                 FOR(j, res.size())
447                                 {
448                                     if(res[j] > score)
449                                     {
450                                         score = res[j];
451                                         winner = j;
452                                     }
453                                 }
454                                 if(winner != testLabels[i]) error += 1.f;
455                                 rocdata.push_back(f32pair(winner, testLabels[i]));
456                             }
457                         }
458                         else
459                         {
460                             bBinary = true;
461                             float res = c->Test(testSamples[i]);
462                             if(res * testBinLabels[i] < 0) error += 1.f;
463                             else invError += 1.f;
464                             rocdata.push_back(f32pair(res, (testBinLabels[i]+1)/2));
465                         }
466                     }
467                     rocdata = FixRocData(rocdata);
468                     if(bBinary) error = min(error, invError);
469                     error /= testSamples.size();
470                     measure1[f] = error;
471                     // we use micro f-measure for multi-class
472                     float eff = bBinary ? GetRocValueAt(rocdata, 0) : GetMicroMacroFMeasure(rocdata).first;
473                     measure2[f] = eff;
474                     DEL(c);
475                 }
476                 else if(clusterer);
477                 else if(regressor)
478                 {
479                     if(!samples.size()) return;
480                     Regressor *r = regressor->GetRegressor();
481                     regressor->SetParams(r, params);
482                     int outputDim = samples[0].size()-1;
483                     r->SetOutputDim(outputDim);
484                     r->Train(trainSamples, trainLabels);
485                     float error = 0;
486                     FOR(i, testSamples.size())
487                     {
488                         fvec res = r->Test(testSamples[i]);
489                         // we compute the mse
490                         error += sqrtf((res[0] - trainSamples[i][outputDim])*(res[0] - trainSamples[i][outputDim]));
491                     }
492                     error /= testSamples.size();
493                     measure1[f] = error;
494                 }
495                 else if(dynamical);
496                 else if(avoider);
497                 else if(maximizer);
498                 else if(reinforcement);
499                 else if(projector);
500             }
501             KILL(perm);
502             // now we fill the error map
503             float mean = 0, effMean = 0;
504             FOR(f, folds)
505             {
506                 mean += measure1[f];
507                 effMean += measure2[f];
508             }
509             mean /= folds;
510             effMean /= folds;
511             qDebug() << "mean" << mean << "fmeasure" << effMean;
512             errorMap[x+y*xSteps] = mean;
513             fmeasureMap[x+y*xSteps] = effMean;
514             ui->progressBar->setValue(x+y*xSteps);
515             ui->progressBar->repaint();
516             qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
517         }
518     }
519     if(classifier)
520     {
521         mapList["Error"] = errorMap;
522         mapList["FMeasure"] = fmeasureMap;
523         map = errorMap;
524     }
525     else if(regressor)
526     {
527         mapList["Error"] = errorMap;
528     }
529     bool bSig = ui->resultCombo->blockSignals(true);
530     ui->resultCombo->clear();
531     for(std::map<QString,fvec>::iterator it = mapList.begin(); it != mapList.end(); it++)
532     {
533         ui->resultCombo->addItem(it->first);
534     }
535     ui->resultCombo->setCurrentIndex(0);
536     ui->resultCombo->blockSignals(bSig);
537     mapX = xSteps;
538     mapY = ySteps;
539     DisplayResults();
540     ui->progressBar->setValue(0);
541     repaint();
542 }
543
544 void GridSearch::OptionsChanged()
545 {
546     int index1 = ui->names1Combo->currentIndex();
547     int index2 = ui->names2Combo->currentIndex();
548     if(index1 < types.size())
549     {
550         bool bList = types[index1] == "List";
551         ui->start1Spin->setEnabled(!bList);
552         ui->stop1Spin->setEnabled(!bList);
553         ui->steps1Spin->setEnabled(!bList);
554         float start=0, stop=99999;
555         if(!bList)
556         {
557             if(values[index1].size() > 0) start = values[index1][0].toFloat();
558             if(values[index1].size() > 1) stop = values[index1][1].toFloat();
559             if(ui->start1Spin->value() < start) ui->start1Spin->setValue(start);
560             if(ui->stop1Spin->value() < ui->start1Spin->value()) ui->stop1Spin->setValue(ui->start1Spin->value()+1);
561             if(ui->stop1Spin->value() > stop) ui->stop1Spin->setValue(stop);
562             ui->steps1Spin->setValue(10);
563             if(types[index1] == "Integer")
564             {
565                 ui->start1Spin->setSingleStep(1);
566                 ui->stop1Spin->setSingleStep(1);
567                 ui->start1Spin->setDecimals(0);
568                 ui->stop1Spin->setDecimals(0);
569             }
570             else if(types[index1] == "Real")
571             {
572                 ui->start1Spin->setSingleStep((stop-start)*0.001);
573                 ui->stop1Spin->setSingleStep((stop-start)*0.001);
574                 ui->start1Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
575                 ui->stop1Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
576             }
577         }
578         else ui->steps1Spin->setValue(values[index1].size());
579     }
580     else
581     {
582         ui->start1Spin->setEnabled(false);
583         ui->stop1Spin->setEnabled(false);
584         ui->steps1Spin->setEnabled(false);
585     }
586     if(index2 < types.size())
587     {
588         bool bList = types[index2] == "List";
589         ui->start2Spin->setEnabled(!bList);
590         ui->stop2Spin->setEnabled(!bList);
591         ui->steps2Spin->setEnabled(!bList);
592         float start=0, stop=99999;
593         if(!bList)
594         {
595             if(values[index2].size() > 0) start = values[index2][0].toFloat();
596             if(values[index2].size() > 1) stop = values[index2][1].toFloat();
597             if(ui->start2Spin->value() < start) ui->start2Spin->setValue(start);
598             if(ui->stop2Spin->value() < ui->start2Spin->value()) ui->stop2Spin->setValue(ui->start2Spin->value()+1);
599             if(ui->stop2Spin->value() > stop) ui->stop2Spin->setValue(stop);
600             ui->steps2Spin->setValue(10);
601             if(types[index2] == "Integer")
602             {
603                 ui->start2Spin->setSingleStep(1);
604                 ui->stop2Spin->setSingleStep(1);
605             }
606             else if(types[index2] == "Real")
607             {
608                 ui->start2Spin->setSingleStep((stop-start)*0.001);
609                 ui->stop2Spin->setSingleStep((stop-start)*0.001);
610                 ui->start2Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
611                 ui->stop2Spin->setDecimals((int)(log((stop-start)*0.001f)/log(10.f)));
612             }
613         }
614         else ui->steps2Spin->setValue(values[index2].size());
615     }
616     else
617     {
618         ui->start2Spin->setEnabled(false);
619         ui->stop2Spin->setEnabled(false);
620         ui->steps2Spin->setEnabled(false);
621     }
622 }
623
624 void GridSearch::Update()
625 {
626     names.clear();
627     types.clear();
628     values.clear();
629     if(classifier)
630         classifier->GetParameterList(names, types, values);
631     if(clusterer)
632         clusterer->GetParameterList(names, types, values);
633     if(regressor)
634         regressor->GetParameterList(names, types, values);
635     if(dynamical)
636         dynamical->GetParameterList(names, types, values);
637     if(avoider)
638         avoider->GetParameterList(names, types, values);
639     if(maximizer)
640         maximizer->GetParameterList(names, types, values);
641     if(reinforcement)
642         reinforcement->GetParameterList(names, types, values);
643     if(projector)
644         projector->GetParameterList(names, types, values);
645     ui->names1Combo->clear();
646     ui->names2Combo->clear();
647     FOR(i, names.size())
648     {
649         ui->names1Combo->addItem(names[i]);
650         ui->names2Combo->addItem(names[i]);
651     }
652     ui->names1Combo->addItem("None");
653     ui->names2Combo->addItem("None");
654     if(names.size() > 0) ui->names1Combo->setCurrentIndex(0);
655     if(names.size() > 1) ui->names2Combo->setCurrentIndex(1);
656 }
657
658 void GridSearch::SetClassifier(ClassifierInterface *c)
659 {
660     if(classifier == c) return;
661     classifier = c;
662     clusterer = 0;
663     regressor = 0;
664     dynamical = 0;
665     avoider = 0;
666     maximizer = 0;
667     reinforcement = 0;
668     projector = 0;
669     pixmap = QPixmap();
670     mousePoint = QPoint(-1,-1);
671     Update();
672 }
673
674 void GridSearch::SetClusterer(ClustererInterface *c)
675 {
676     if(clusterer == c) return;
677     classifier = 0;
678     clusterer = c;
679     regressor = 0;
680     dynamical = 0;
681     avoider = 0;
682     maximizer = 0;
683     reinforcement = 0;
684     projector = 0;
685     pixmap = QPixmap();
686     mousePoint = QPoint(-1,-1);
687     Update();
688 }
689
690 void GridSearch::SetRegressor(RegressorInterface *c)
691 {
692     if(regressor == c) return;
693     classifier = 0;
694     clusterer = 0;
695     regressor = c;
696     dynamical = 0;
697     avoider = 0;
698     maximizer = 0;
699     reinforcement = 0;
700     projector = 0;
701     pixmap = QPixmap();
702     mousePoint = QPoint(-1,-1);
703     Update();
704 }
705
706 void GridSearch::SetDynamical(DynamicalInterface *c)
707 {
708     if(dynamical == c) return;
709     classifier = 0;
710     clusterer = 0;
711     regressor = 0;
712     dynamical = c;
713     avoider = 0;
714     maximizer = 0;
715     reinforcement = 0;
716     projector = 0;
717     pixmap = QPixmap();
718     mousePoint = QPoint(-1,-1);
719     Update();
720 }
721
722 void GridSearch::SetAvoidance(AvoidanceInterface *c)
723 {
724     if(avoider == c) return;
725     classifier = 0;
726     clusterer = 0;
727     regressor = 0;
728     dynamical = 0;
729     avoider = c;
730     maximizer = 0;
731     reinforcement = 0;
732     projector = 0;
733     pixmap = QPixmap();
734     mousePoint = QPoint(-1,-1);
735     Update();
736 }
737
738 void GridSearch::SetMaximizer(MaximizeInterface *c)
739 {
740     if(maximizer == c) return;
741     classifier = 0;
742     clusterer = 0;
743     regressor = 0;
744     dynamical = 0;
745     avoider = 0;
746     maximizer = c;
747     reinforcement = 0;
748     projector = 0;
749     pixmap = QPixmap();
750     mousePoint = QPoint(-1,-1);
751     Update();
752 }
753
754 void GridSearch::SetReinforcement(ReinforcementInterface *c)
755 {
756     if(reinforcement == c) return;
757     classifier = 0;
758     clusterer = 0;
759     regressor = 0;
760     dynamical = 0;
761     avoider = 0;
762     maximizer = 0;
763     reinforcement = c;
764     projector = 0;
765     pixmap = QPixmap();
766     mousePoint = QPoint(-1,-1);
767     Update();
768 }
769
770 void GridSearch::SetProjector(ProjectorInterface *c)
771 {
772     if(projector == c) return;
773     classifier = 0;
774     clusterer = 0;
775     regressor = 0;
776     dynamical = 0;
777     avoider = 0;
778     maximizer = 0;
779     reinforcement = 0;
780     projector = c;
781     pixmap = QPixmap();
782     mousePoint = QPoint(-1,-1);
783     Update();
784 }