NTRT Simulator  v1.1
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
AnnealEvolution.cpp
Go to the documentation of this file.
1 /*
2  * Copyright © 2012, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
7  * under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * http://www.apache.org/licenses/LICENSE-2.0.
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
15  * either express or implied. See the License for the specific language
16  * governing permissions and limitations under the License.
17 */
18 
28 #include "AnnealEvolution.h"
30 #include "core/tgString.h"
31 #include "helpers/FileHelpers.h"
32 #include <iostream>
33 #include <numeric>
34 #include <string>
35 #include <sstream>
36 #include <stdexcept>
37 
38 using namespace std;
39 
40 #ifdef _WIN32
41 
42 // Windows
43 #define rdtsc __rdtsc
44 
45 #else
46 
47 // For everything else
48 unsigned long long rdtsc(){
49  unsigned int lo,hi;
50  __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
51  return ((unsigned long long)hi << 32) | lo;
52 }
53 
54 #endif
55 
56 AnnealEvolution::AnnealEvolution(std::string suff, std::string config, std::string path) :
57 suffix(suff),
58 Temp(1.0)
59 {
60  currentTest=0;
61  generationNumber=0;
62 
63  if (path != "")
64  {
65  resourcePath = FileHelpers::getResourcePath(path);
66  }
67  else
68  {
69  resourcePath = "";
70  }
71 
72  std::string configPath = resourcePath + config;
73 
74  configuration myconfigdataaa;
75  myconfigdataaa.readFile(configPath);
76  populationSize=myconfigdataaa.getintvalue("populationSize");
77  numberOfElementsToMutate=myconfigdataaa.getintvalue("numberOfElementsToMutate");
78  numberOfTestsBetweenGenerations=myconfigdataaa.getintvalue("numberOfTestsBetweenGenerations");
79  numberOfControllers=myconfigdataaa.getintvalue("numberOfControllers"); //shared with ManhattanToyController
80  leniencyCoef=myconfigdataaa.getDoubleValue("leniencyCoef");
81  coevolution=myconfigdataaa.getintvalue("coevolution");
82  seeded = myconfigdataaa.getintvalue("startSeed");
83 
84  bool learning = myconfigdataaa.getintvalue("learning");
85 
86  srand(rdtsc());
87  eng.seed(rdtsc());
88 
89  for(int j=0;j<numberOfControllers;j++)
90  {
91  populations.push_back(new AnnealEvoPopulation(populationSize,myconfigdataaa));
92  }
93 
94  // Overwrite the random parameters based on data
95  if(seeded) // Test that the file exists
96  {
97  for(int i = 0; i < numberOfControllers; i++)
98  {
99  AnnealEvoMember* seededPop = populations[i]->controllers.back();
100  stringstream ss;
101  ss<< resourcePath <<"logs/bestParameters-"<<this->suffix<<"-"<<i<<".nnw";
102  seededPop->loadFromFile(ss.str().c_str());
103  }
104  }
105  if(learning)
106  {
107  evolutionLog.open((resourcePath + "logs/evolution" + suffix + ".csv").c_str(),ios::out);
108  if (!evolutionLog.is_open())
109  {
110  throw std::runtime_error("Logs does not exist. Please create a logs folder in your build directory or update your cmake file");
111  }
112  }
113 }
114 
115 AnnealEvolution::~AnnealEvolution()
116 {
117  // @todo - solve the invalid pointer that occurs here
118  #if (0)
119  for(std::size_t i = 0; i < populations.size(); i++)
120  {
121  delete populations[i];
122  }
123  populations.clear();
124  #endif
125 }
126 
127 void AnnealEvolution::mutateEveryController()
128 {
129  for(std::size_t i=0;i<populations.size();i++)
130  {
131  populations.at(i)->mutate(&eng,numberOfElementsToMutate, Temp);
132  }
133 }
134 
135 
136 
137 void AnnealEvolution::orderAllPopulations()
138 {
139  generationNumber++;
140  double aveScore1 = 0.0;
141  double aveScore2 = 0.0;
142 #if (0)
143  // Disable definition of unused variables to suppress compiler warning
144  double maxScore1,maxScore2;
145 #endif
146  for(std::size_t i=0;i<scoresOfTheGeneration.size();i++)
147  {
148  aveScore1+=scoresOfTheGeneration[i][0];
149  aveScore2+=scoresOfTheGeneration[i][1];
150  }
151  aveScore1 /= scoresOfTheGeneration.size();
152  aveScore2 /= scoresOfTheGeneration.size();
153 
154 
155  for(std::size_t i=0;i<populations.size();i++)
156  {
157  populations.at(i)->orderPopulation();
158  }
159  evolutionLog<<generationNumber*numberOfTestsBetweenGenerations<<","<<aveScore1<<","<<aveScore2<<",";
160  evolutionLog<<populations.at(0)->getMember(0)->maxScore<<","<<populations.at(0)->getMember(0)->maxScore1<<","<<populations.at(0)->getMember(0)->maxScore2<<endl;
161 
162 
163  // what if member at 0 isn't the best of all time for some reason?
164  // This seems biased towards average scores
165  // We actually order the populations, so member 0 is the current best according to the assigned fitness
166  ofstream logfileLeader;
167  for(std::size_t i=0;i<populations.size();i++)
168  {
169  stringstream ss;
170  ss << resourcePath << "logs/bestParameters-" << suffix << "-" << i << ".nnw";
171 
172  populations[i]->getMember(0)->saveToFile(ss.str().c_str());
173  }
174 }
175 
176 #if (0)
177 double diffclock(clock_t clock1,clock_t clock2)
178 {
179  double diffticks=clock1-clock2;
180  double diffms=(diffticks*10)/CLOCKS_PER_SEC;
181  return diffms;
182 }
183 #endif
184 
185 vector <AnnealEvoMember *> AnnealEvolution::nextSetOfControllers()
186 {
187  int testsToDo=0;
188  if(coevolution)
189  testsToDo=numberOfTestsBetweenGenerations; //stop when we reach x amount of random tests
190  else
191  testsToDo=populationSize; //stop when we test each element once
192 
193  if(currentTest == testsToDo)
194  {
195  orderAllPopulations();
196  mutateEveryController();
197  Temp -= 0.0; // @todo - make this a parameter
198 // cout<<"mutated the populations"<<endl;
199  this->scoresOfTheGeneration.clear();
200 
201  if(coevolution)
202  currentTest=0;//Start from 0
203  else
204  currentTest=populationSize-numberOfElementsToMutate; //start from the mutated ones only (last x)
205  }
206 
207  selectedControllers.clear();
208  for(std::size_t i=0;i<populations.size();i++)
209  {
210  int selectedOne=0;
211  if(coevolution)
212  selectedOne=rand()%populationSize; //select random one from each pool
213  else
214  selectedOne=currentTest; //select the same from each pool
215 
216 // cout<<"selected: "<<selectedOne<<endl;
217  selectedControllers.push_back(populations.at(i)->getMember(selectedOne));
218  }
219  currentTest++;
220 // cout<<"currentTest:"<<currentTest<<endl;
221 
222  return selectedControllers;
223 }
224 
225 void AnnealEvolution::updateScores(vector <double> multiscore)
226 {
227  if(multiscore.size()==2)
228  this->scoresOfTheGeneration.push_back(multiscore);
229  else
230  multiscore.push_back(-1.0);
231  double score=1.0* multiscore[0] - 0.0 * multiscore[1];
232 
233  //Record it to the file
234  ofstream payloadLog;
235  payloadLog.open((resourcePath + "logs/scores.csv").c_str(),ios::app);
236  payloadLog<<multiscore[0]<<","<<multiscore[1];
237 
238  for(std::size_t oneElem=0;oneElem<selectedControllers.size();oneElem++)
239  {
240  AnnealEvoMember * controllerPointer=selectedControllers.at(oneElem);
241 
242  controllerPointer->pastScores.push_back(score);
243  double prevScore=controllerPointer->maxScore;
244  if(prevScore>score)
245  {
246  double newScore= leniencyCoef * prevScore + (1.0 - leniencyCoef) * score;
247  controllerPointer->maxScore=newScore;
248  }
249  else
250  {
251  controllerPointer->maxScore=score;
252  controllerPointer->maxScore1=multiscore[0];
253  controllerPointer->maxScore2=multiscore[1];
254  }
255  std::size_t n = controllerPointer->statelessParameters.size();
256  for (std::size_t i = 0; i < n; i++)
257  {
258  payloadLog << "," << controllerPointer->statelessParameters[i];
259  }
260  }
261 
262  payloadLog<<endl;
263  payloadLog.close();
264  return;
265 }
Convenience function for combining strings with ints, mostly for naming structures.
std::string resourcePath
A class to read a learning configuration from a .ini file.
A series of functions to assist with file input/output.
Contains the definition of class AnnealEvolution. Adapting NeuroEvolution to do Simulated Annealing...