- Integrated the file import into the main interface (not as a plugin anymore)
[mldemos:mldemos.git] / Core / datasetManager.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 "public.h"
21 #include "basicMath.h"
22 #include "mymaths.h"
23 #include "datasetManager.h"
24 #include <fstream>
25 #include <algorithm>
26 #include <map>
27
28 using namespace std;
29
30 /******************************************/
31 /*                                        */
32 /*    DATASET MANAGER                     */
33 /*                                        */
34 /******************************************/
35 u32 DatasetManager::IDCount = 0;
36
37 DatasetManager::DatasetManager(int dimension)
38 : size(dimension)
39 {
40     bProjected = false;
41         ID = IDCount++;
42         perm = NULL;
43 }
44
45 DatasetManager::~DatasetManager()
46 {
47         Clear();
48 }
49
50 void DatasetManager::Clear()
51 {
52     bProjected = false;
53         samples.clear();
54         obstacles.clear();
55         flags.clear();
56         labels.clear();
57         sequences.clear();
58         rewards.Clear();
59         KILL(perm);
60 }
61
62 void DatasetManager::AddSample(fvec sample, int label, dsmFlags flag)
63 {
64         if (!sample.size()) return;
65         size = sample.size();
66
67         samples.push_back(sample);
68         labels.push_back(label);
69         flags.push_back(flag);
70         KILL(perm);
71         perm = randPerm(samples.size());
72 }
73
74 void DatasetManager::AddSamples(std::vector< fvec > newSamples, ivec newLabels, std::vector<dsmFlags> newFlags)
75 {
76         FOR(i, newSamples.size())
77         {
78                 if(newSamples[0].size()) size = newSamples[0].size();
79                 if(newSamples[i].size())
80                 {
81                         samples.push_back(newSamples[i]);
82                         if(i < newFlags.size()) flags.push_back(newFlags[i]);
83                         else flags.push_back(_UNUSED);
84                 }
85         }
86         if(newLabels.size() == newSamples.size()) FOR(i, newLabels.size()) labels.push_back(newLabels[i]);
87         else FOR(i, newSamples.size()) labels.push_back(0);
88         KILL(perm);
89         perm = randPerm(samples.size());
90 }
91
92 void DatasetManager::AddSamples(DatasetManager &newSamples)
93 {
94         AddSamples(newSamples.GetSamples(), newSamples.GetLabels(), newSamples.GetFlags());
95 }
96
97 void DatasetManager::RemoveSample(unsigned int index)
98 {
99         if(index >= samples.size()) return;
100         if(samples.size() == 1)
101         {
102                 Clear();
103                 return;
104         }
105         samples[index].clear();
106         for (unsigned int i = index; i < samples.size()-1; i++)
107         {
108                 samples[i] = samples[i+1];
109                 labels[i] = labels[i+1];
110                 flags[i] = flags[i+1];
111         }
112         samples.pop_back();
113         labels.pop_back();
114         flags.pop_back();
115
116         // we need to check if a sequence needs to be shortened
117         FOR(i, sequences.size())
118         {
119                 if(sequences[i].first > index) // later sequences
120                 {
121                         sequences[i].first--;
122                         sequences[i].second--;
123                 }
124                 else if(sequences[i].first == index || sequences[i].second >= index)
125                 {
126                         sequences[i].second--;
127                 }
128                 if(sequences[i].first >= sequences[i].second) // we need to pop out the sequence
129                 {
130                         if(sequences[i].first == sequences[i].second)
131                         {
132                                 flags[sequences[i].first] = _UNUSED;
133                         }
134                         for(int j=i; j<sequences.size()-1; j++)
135                         {
136                                 sequences[j] = sequences[j+1];
137                         }
138                         sequences.pop_back();
139                         i--;
140                 }
141         }
142 }
143
144 void DatasetManager::RemoveSamples(ivec indices)
145 {
146     if(indices.size() > samples.size()) return;
147     // we sort the indices
148     sort(indices.begin(), indices.end(), less<int>());
149     int offset = 0;
150     FOR(i, indices.size())
151     {
152         int index = indices[i] - offset;
153         if(index < 0 || index > samples.size()) continue;
154         RemoveSample(index);
155         offset++;
156     }
157 }
158
159 void DatasetManager::AddSequence(int start, int stop)
160 {
161         if(start >= samples.size() || stop >= samples.size()) return;
162         for(int i=start; i<=stop; i++) flags[i] = _TRAJ;
163         sequences.push_back(ipair(start,stop));
164         // sort sequences by starting value
165         std::sort(sequences.begin(), sequences.end());
166 }
167
168 void DatasetManager::AddSequence(ipair newSequence)
169 {
170         if(newSequence.first >= samples.size() || newSequence.second >= samples.size()) return;
171         for(int i=newSequence.first; i<=newSequence.second; i++) flags[i] = _TRAJ;
172         sequences.push_back(newSequence);
173         // sort sequences by starting value
174         std::sort(sequences.begin(), sequences.end());
175 }
176
177 void DatasetManager::AddSequences(std::vector< ipair > newSequences)
178 {
179         sequences.reserve(sequences.size()+newSequences.size());
180         FOR(i, newSequences.size())
181         {
182                 sequences.push_back(newSequences[i]);           
183         }
184 }
185
186 void DatasetManager::RemoveSequence(unsigned int index)
187 {
188         if(index >= sequences.size()) return;
189         for(int i=index; i<sequences.size()-1; i++) sequences[i] = sequences[i+1];
190         sequences.pop_back();
191 }
192
193 void DatasetManager::AddTimeSerie(std::string name, std::vector<fvec> data, std::vector<long int>  timestamps)
194 {
195         TimeSerie serie;
196         serie.name = name;
197         serie.data = data;
198         serie.timestamps = timestamps;
199         AddTimeSerie(serie);
200 }
201
202 void DatasetManager::AddTimeSerie(TimeSerie serie)
203 {
204         series.push_back(serie);
205 }
206
207 void DatasetManager::AddTimeSeries(std::vector< TimeSerie > newTimeSeries)
208 {
209         series.insert(series.end(), newTimeSeries.begin(), newTimeSeries.end());
210 }
211
212 void DatasetManager::RemoveTimeSerie(unsigned int index)
213 {
214         if(index >= series.size()) return;
215         series.erase(series.begin() + index);
216 }
217
218 void DatasetManager::AddObstacle(fvec center, fvec axes, float angle, fvec power, fvec repulsion)
219 {
220         Obstacle o;
221         o.center = center;
222         o.axes = axes;
223         o.angle = angle;
224         o.power = power;
225         o.repulsion = repulsion;
226         obstacles.push_back(o);
227 }
228
229 void DatasetManager::AddObstacles(std::vector<Obstacle> newObstacles)
230 {
231         FOR(i, newObstacles.size()) obstacles.push_back(newObstacles[i]);
232 }
233
234 void DatasetManager::RemoveObstacle(unsigned int index)
235 {
236         if(index >= obstacles.size()) return;
237         for(int i=index; i<obstacles.size()-1; i++) obstacles[i] = obstacles[i+1];
238         obstacles.pop_back();
239 }
240
241 void DatasetManager::AddReward(float *values, ivec size, fvec lowerBoundary, fvec higherBoundary)
242 {
243         rewards.SetReward(values, size, lowerBoundary, higherBoundary);
244 }
245
246 // we compare the current sample with all the ones in the dataset
247 // and return the smallest distance
248 double DatasetManager::Compare(fvec sample)
249 {
250         if(!sample.size()) return 1.0;
251
252         // now compute the differences
253         double minDist = 1.0;
254         u32 index = 0;
255         FOR(i, samples.size())
256         {
257                 double dist = 0;
258                 FOR(j, size) dist += fabs(sample[j]-samples[i][j]);
259                 dist /= size;
260                 if(minDist > dist)
261                 {
262                         index = i;
263                         minDist = dist;
264                 }
265         }
266         return minDist;
267 }
268
269 void DatasetManager::Randomize(int seed)
270 {
271         KILL(perm);
272         if(samples.size()) perm = randPerm(samples.size(), seed);
273 }
274
275 void DatasetManager::ResetFlags()
276 {
277         FOR(i, samples.size()) flags[i] = _UNUSED;
278 }
279
280 void DatasetManager::SetSample(int index, fvec sample)
281 {
282         if(index >= 0 && index < samples.size()) samples[index] = sample;
283 }
284
285 fvec DatasetManager::GetSampleDim(int index, ivec inputDims, int outputDim)
286 {
287     if(index>=samples.size()) return fvec();
288     if(!inputDims.size()) return samples[index];
289     int dim = inputDims.size();
290     fvec sample(dim + outputDim!=-1?1:0);
291     FOR(d, dim) sample[d] = samples[index][inputDims[d]];
292     if(outputDim != -1) sample[dim] = samples[index][outputDim];
293     return sample;
294 }
295
296 std::vector< fvec > DatasetManager::GetSampleDims(ivec inputDims, int outputDim)
297 {
298     if(!inputDims.size()) return samples;
299
300     vector<fvec> newSamples = samples;
301     int newDim = inputDims.size() + (outputDim != -1 ? 1 : 0);
302     FOR(i, samples.size())
303     {
304         fvec newSample(newDim);
305         FOR(d, inputDims.size())
306         {
307             newSample[d] = samples[i][inputDims[d]];
308         }
309         if(outputDim != -1) newSample[newDim-1] = samples[i][outputDim];
310         newSamples[i] = newSample;
311     }
312     return newSamples;
313 }
314
315 std::vector< fvec > DatasetManager::GetSamples(u32 count, dsmFlags flag, dsmFlags replaceWith)
316 {
317         std::vector< fvec > selected;
318         if (!samples.size() || !perm) return selected;
319
320         if (!count)
321         {
322                 FOR(i, samples.size())
323                 {
324                         if ( flags[perm[i]] == flag)
325                         {
326                                 selected.push_back(samples[perm[i]]);
327                                 flags[perm[i]] = replaceWith;
328                         }
329                 }
330                 return selected;
331         }
332
333         for ( u32 i=0, cnt=0; i < samples.size() && cnt < count; i++ )
334         {
335                 if ( flags[perm[i]] == flag )
336                 {
337                         selected.push_back(samples[perm[i]]);
338                         flags[perm[i]] = replaceWith;
339                         cnt++;
340                 }
341         }
342
343         return selected;
344 }
345
346 std::vector< std::vector < fvec > > DatasetManager::GetTrajectories(int resampleType, int resampleCount, int centerType, float dT, int zeroEnding)
347 {
348
349         // we split the data into trajectories
350         vector< vector<fvec> > trajectories;
351         if(!sequences.size() || !samples.size()) return trajectories;
352         int dim = samples[0].size();
353         trajectories.resize(sequences.size());
354         FOR(i, sequences.size())
355         {
356                 int length = sequences[i].second-sequences[i].first+1;
357                 trajectories[i].resize(length);
358                 FOR(j, length)
359                 {
360                         trajectories[i][j].resize(dim*2);
361                         // copy data
362                         FOR(d, dim) trajectories[i][j][d] = samples[sequences[i].first + j][d];
363                 }
364         }
365
366         switch(resampleType)
367         {
368         case 0: // none
369         {
370                 FOR(i,sequences.size())
371                 {
372                         int cnt = sequences[i].second-sequences[i].first+1;
373                         if(resampleCount > cnt) resampleCount = cnt;
374                 }
375                 FOR(i, trajectories.size())
376                 {
377                         while(trajectories[i].size() > resampleCount) trajectories[i].pop_back();
378                 }
379         }
380                 break;
381         case 1: // uniform
382         {
383                 FOR(i, trajectories.size())
384                 {
385                         vector<fvec> trajectory = trajectories[i];
386                         trajectories[i] = interpolate(trajectory, resampleCount);
387                 }
388         }
389                 break;
390         case 2: // spline
391         {
392                 FOR(i, trajectories.size())
393                 {
394                         vector<fvec> trajectory = trajectories[i];
395                         trajectories[i] = interpolateSpline(trajectory, resampleCount);
396                 }
397         }
398                 break;
399         }
400
401
402         if(centerType)
403         {
404                 map<int,int> counts;
405                 map<int,fvec> centers;
406                 vector<int> trajLabels(sequences.size());
407                 FOR(i, sequences.size())
408                 {
409                         int index = centerType==1 ? sequences[i].second : sequences[i].first; // start
410                         int label = GetLabel(index);
411                         trajLabels[i] = label;
412                         if(!centers.count(label))
413                         {
414                                 fvec center(dim,0);
415                                 centers[label] = center;
416                                 counts[label] = 0;
417                         }
418                         centers[label] += samples[index];
419                         counts[label]++;
420                 }
421                 for(map<int,int>::iterator p = counts.begin(); p!=counts.end(); ++p)
422                 {
423                         int label = p->first;
424                         centers[label] /= p->second;
425                 }
426                 FOR(i, trajectories.size())
427                 {
428                         if(centerType == 1)
429                         {
430                                 fvec difference = centers[trajLabels[i]] - trajectories[i].back();
431                                 FOR(j, resampleCount) trajectories[i][j] += difference;
432                         }
433                         else
434                         {
435                                 fvec difference = centers[trajLabels[i]] - trajectories[i][0];
436                                 FOR(j, resampleCount) trajectories[i][j] += difference;
437                         }
438                 }
439         }
440
441         float maxV = -FLT_MAX;
442         // we compute the velocity
443         FOR(i, trajectories.size())
444         {
445                 FOR(j, resampleCount-1)
446                 {
447                         FOR(d, dim)
448                         {
449                                 float velocity = (trajectories[i][j+1][d] - trajectories[i][j][d]) / dT;
450                                 trajectories[i][j][dim + d] = velocity;
451                                 if(velocity > maxV) maxV = velocity;
452                         }
453                 }
454                 if(!zeroEnding)
455                 {
456                         FOR(d, dim)
457                         {
458                                 trajectories[i][resampleCount-1][dim + d] = trajectories[i][resampleCount-2][dim + d];
459                         }
460                 }
461         }
462
463         // we normalize the velocities as the variance of the data
464         fvec mean, sigma;
465         mean.resize(dim,0);
466         int cnt = 0;
467         sigma.resize(dim,0);
468         FOR(i, trajectories.size())
469         {
470                 FOR(j, resampleCount)
471                 {
472                         mean += trajectories[i][j];
473                         cnt++;
474                 }
475         }
476         mean /= cnt;
477         FOR(i, trajectories.size())
478         {
479                 FOR(j, resampleCount)
480                 {
481                         fvec diff = (mean - trajectories[i][j]);
482                         FOR(d,dim) sigma[d] += diff[d]*diff[d];
483                 }
484         }
485         sigma /= cnt;
486
487         FOR(i, trajectories.size())
488         {
489                 FOR(j, resampleCount)
490                 {
491                         FOR(d, dim)
492                         {
493                                 trajectories[i][j][dim + d] /= maxV;
494                                 //trajectories[i][j][dim + d] /= sqrt(sigma[d]);
495                         }
496                 }
497         }
498         return trajectories;
499 }
500
501
502 void DatasetManager::Save(const char *filename)
503 {
504         if(!samples.size()) return;
505         u32 sampleCnt = samples.size();
506
507         ofstream file(filename);
508         if(!file.is_open()) return;
509
510         file << sampleCnt << " " << size << "\n";
511         FOR(i, sampleCnt)
512         {
513                 FOR(j,size)
514                 {
515                         file << samples[i][j] << " ";
516                 }
517                 file << labels[i] << " ";
518                 file << flags[i] << " ";
519                 file << "\n";
520         }
521
522         if(sequences.size())
523         {
524                 file << "s " << sequences.size() << "\n";
525                 FOR(i, sequences.size())
526                 {
527                         file << sequences[i].first << " " << sequences[i].second << "\n";
528                 }
529         }
530
531         // we load the obstacles
532         if(obstacles.size())
533         {
534                 file << "o " << obstacles.size() << "\n";
535                 FOR(i, obstacles.size())
536                 {
537                         FOR(j, size) file << obstacles[i].center[j] << " ";
538                         FOR(j, size) file << obstacles[i].axes[j] << " ";
539                         file << obstacles[i].angle << " ";
540                         file << obstacles[i].power[0] << " ";
541                         file << obstacles[i].power[1] << " ";
542                         file << obstacles[i].repulsion[0] << " ";
543                         file << obstacles[i].repulsion[1] << "\n";
544                 }
545         }
546
547         file.close();
548 }
549
550 bool DatasetManager::Load(const char *filename)
551 {
552         ifstream file(filename);
553         if(!file.is_open()) return false;
554         Clear();
555
556         int sampleCnt;
557         file >> sampleCnt;
558         file >> size;
559
560         // we load the samples
561         FOR(i, sampleCnt)
562         {
563                 fvec sample;
564                 sample.resize(size,0);
565                 int label, flag;
566                 FOR(j, size)
567                 {
568                         file >> sample[j];
569                 }
570                 file >> label;
571                 file >> flag;
572                 samples.push_back(sample);
573                 labels.push_back(label);
574                 flags.push_back((dsmFlags)flag);
575         }
576
577         // we load the sequences
578         char tmp[255];
579         file.getline(tmp,255); // we skip the rest of the line
580         int nextChar = file.peek();
581         if(nextChar == 's') // we have sequences!
582         {
583                 char dump;
584                 file >> dump;
585                 int sequenceCount;
586                 file >> sequenceCount;
587                 FOR(i, sequenceCount)
588                 {
589                         int start, stop;
590                         file >> start;
591                         file >> stop;
592                         sequences.push_back(ipair(start,stop));
593                 }
594                 file.getline(tmp,255);
595                 nextChar = file.peek();
596         }
597         // we load the obstacles
598         if(nextChar == 'o')
599         {
600                 char dump;
601                 file >> dump;
602                 int obstacleCount;
603                 file >> obstacleCount;
604                 Obstacle obstacle;
605                 obstacle.center.resize(size);
606                 obstacle.axes.resize(size);
607                 obstacle.power.resize(size);
608                 obstacle.repulsion.resize(size);
609                 FOR(i, obstacleCount)
610                 {
611                         FOR(j, size) file >> obstacle.center[j];
612                         FOR(j, size) file >> obstacle.axes[j];
613                         file >> obstacle.angle;
614                         FOR(j, size) file >> obstacle.power[j];
615                         FOR(j, size) file >> obstacle.repulsion[j];
616                         obstacles.push_back(obstacle);
617                 }
618         }
619
620         file.close();
621         KILL(perm);
622         perm = randPerm(samples.size());
623         return samples.size() > 0;
624 }
625
626 int DatasetManager::GetDimCount()
627 {
628         int dim = 2;
629         if(samples.size()) dim = samples[0].size();
630         if(series.size() && series[0].size())
631         {
632                 dim = series[0][0].size()+1;
633         }
634         return dim;
635 }
636
637 std::pair<fvec, fvec> DatasetManager::GetBounds()
638 {
639     if(!samples.size()) return make_pair(fvec(),fvec());
640     int dim = samples[0].size();
641     fvec mins(dim,FLT_MAX), maxes(dim,-FLT_MAX);
642     FOR(i, samples.size())
643     {
644         fvec& sample = samples[i];
645         int dim = sample.size();
646         FOR(d,dim)
647         {
648             if(mins[d] > sample[d]) mins[d] = sample[d];
649             if(maxes[d] < sample[d]) maxes[d] = sample[d];
650         }
651     }
652     return make_pair(mins, maxes);
653 }
654
655 u32 DatasetManager::GetClassCount(ivec classes)
656 {
657         u32 counts[256];
658         memset(counts, 0, 256*sizeof(u32));
659         FOR(i, classes.size()) counts[classes[i]]++;
660         u32 result = 0;
661         for (u32 i=1; i<256; i++) result += counts[i] > 0 ? 1 : 0;
662         return result;
663 }
664
665 bvec DatasetManager::GetFreeFlags()
666 {
667         bvec res;
668         FOR(i, flags.size()) res.push_back(flags[i] == _UNUSED);
669         return res;
670 }
671
672
673 /******************************************/
674 /*                                        */
675 /*    REWARD MAPS                         */
676 /*                                        */
677 /******************************************/
678 RewardMap& RewardMap::operator= (const RewardMap& r)
679 {
680   if (this != &r) {
681           dim = r.dim;
682           size = r.size;
683           length = r.length;
684           lowerBoundary = r.lowerBoundary;
685           higherBoundary = r.higherBoundary;
686           if(rewards) delete [] rewards;
687           rewards = new float[length];
688           memcpy(rewards, r.rewards, length*sizeof(float));
689   }
690   return *this;
691 }
692
693 void RewardMap::SetReward(float *rewards, ivec size, fvec lowerBoundary, fvec higherBoundary)
694 {
695         this->lowerBoundary = lowerBoundary;
696         this->higherBoundary = higherBoundary;
697         this->size = size;
698         dim = size.size();
699         length = 1;
700         FOR(i, size.size()) length *= size[i];
701         if(this->rewards) delete [] this->rewards;
702         this->rewards = new float[length];
703         memcpy(this->rewards, rewards, length*sizeof(float));
704 }
705
706 void RewardMap::Clear()
707 {
708         dim = 0;
709         size.clear();
710         length = 0;
711         lowerBoundary.clear();
712         higherBoundary.clear();
713         if(rewards) delete [] rewards;
714 }
715
716 void RewardMap::Zero()
717 {
718         FOR(i, length) rewards[i] = 0;
719 }
720
721 // return the value of the reward function at the coordinates provided
722 float RewardMap::ValueAt(fvec sample)
723 {
724         if(!rewards) return 0.f;
725         ivec index;
726         index.resize(dim);
727         FOR(d, dim)
728         {
729                 //we check if we're outside the boundaries
730                 if(sample[d] < lowerBoundary[d]) sample[d] = lowerBoundary[d];
731                 if(sample[d] > higherBoundary[d]) sample[d] = higherBoundary[d];
732                 // now we get the closest index on the map
733                 index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]);
734         }
735
736         // we convert the map index to a vector index
737         int rewardIndex = 0;
738         FOR(d,dim)
739         {
740                 rewardIndex = rewardIndex*size[dim-d-1]+index[dim-d-1];
741         }
742
743         //printf("sample: %f %f index: %d %d (%d) value: %f\n", sample[0], sample[1], index[0], index[1], rewardIndex, rewards[rewardIndex]);
744         // TODO: return interpolation of closest indices instead of the closest index itself
745         return rewards[rewardIndex];
746 }
747
748 void RewardMap::SetValueAt(fvec sample, float value)
749 {
750         if(!rewards) return;
751         ivec index;
752         index.resize(dim);
753         FOR(d, dim)
754         {
755                 //we check if we're outside the boundaries
756                 if(sample[d] < lowerBoundary[d]) return;
757                 if(sample[d] > higherBoundary[d]) return;
758                 // now we get the closest index on the map
759                 index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]);
760         }
761
762         // we convert the map index to a vector index
763         int rewardIndex = 0;
764         FOR(d,dim)
765         {
766                 rewardIndex = rewardIndex*size[dim-d-1]+index[dim-d-1];
767         }
768         rewards[rewardIndex] = value;
769 }
770
771 void RewardMap::ShiftValueAt(fvec sample, float shift)
772 {
773         if(!rewards) return;
774         ivec index;
775         index.resize(dim);
776         FOR(d, dim)
777         {
778                 //we check if we're outside the boundaries
779                 if(sample[d] < lowerBoundary[d]) return;
780                 if(sample[d] > higherBoundary[d]) return;
781                 // now we get the closest index on the map
782                 index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]);
783         }
784         // we convert the map index to a vector index
785         int rewardIndex = 0;
786         FOR(d,dim)
787         {
788                 rewardIndex = rewardIndex*size[dim-d-1]+index[dim-d-1];
789         }
790         printf("index: %d value: %f\n", rewardIndex, rewards[rewardIndex]);
791         rewards[rewardIndex] += shift;
792 }
793
794 void RewardMap::ShiftValueAt(fvec sample, float radius, float shift)
795 {
796         if(!rewards) return;
797         ivec index;
798         index.resize(dim);
799         ivec lowIndex = index, hiIndex = index;
800         ivec steps; steps.resize(dim);
801         FOR(d, dim)
802         {
803                 //we check if we're outside the boundaries
804                 if(sample[d] < lowerBoundary[d]) return;
805                 if(sample[d] > higherBoundary[d]) return;
806                 // now we get the closest index on the map
807                 steps[d] = (int)(2*radius / (higherBoundary[d] - lowerBoundary[d]) * size[d]);
808                 index[d] = (int)((sample[d] - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]);
809                 lowIndex[d] = (int)((sample[d] - radius - lowerBoundary[d]) / (higherBoundary[d] - lowerBoundary[d]) * size[d]);
810         }
811         FOR(i, steps[1])
812         {
813                 FOR(j, steps[0])
814                 {
815                         float x = 2.f*(j - steps[0]*0.5f)/float(steps[0]);
816                         float y = 2.f*(i - steps[1]*0.5f)/float(steps[0]);
817                         if(x*x + y*y > 1) continue;
818                         // we convert the map index to a vector index
819                         int rewardIndex = index[0] - steps[0]/2 + j + (index[1] - steps[1]/2 + i)*size[0];
820                         if(rewardIndex < 0 || rewardIndex>=length) return;
821                         rewards[rewardIndex] += shift;
822                 }
823         }
824 }