NTRT Simulator
 All Classes 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 <iostream>
31 #include <numeric>
32 #include <string>
33 #include <sstream>
34 
35 using namespace std;
36 
37 #ifdef _WIN32
38 
39 // Windows
40 #define rdtsc __rdtsc
41 
42 #else
43 
44 // For everything else
45 unsigned long long rdtsc(){
46  unsigned int lo,hi;
47  __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
48  return ((unsigned long long)hi << 32) | lo;
49 }
50 
51 #endif
52 
53 AnnealEvolution::AnnealEvolution(string suff, string config) :
54 Temp(1.0)
55 {
56  suffix=suff;
57  currentTest=0;
58  generationNumber=0;
59 
60  configuration myconfigdataaa;
61  myconfigdataaa.readFile(config);
62  populationSize=myconfigdataaa.getintvalue("populationSize");
63  numberOfElementsToMutate=myconfigdataaa.getintvalue("numberOfElementsToMutate");
64  numberOfTestsBetweenGenerations=myconfigdataaa.getintvalue("numberOfTestsBetweenGenerations");
65  numberOfControllers=myconfigdataaa.getintvalue("numberOfControllers"); //shared with ManhattanToyController
66  leniencyCoef=myconfigdataaa.getDoubleValue("leniencyCoef");
67  coevolution=myconfigdataaa.getintvalue("coevolution");
68  seeded = myconfigdataaa.getintvalue("startSeed");
69 
70  bool learning = myconfigdataaa.getintvalue("learning");
71 
72  srand(rdtsc());
73  eng.seed(rdtsc());
74 
75  for(int j=0;j<numberOfControllers;j++)
76  {
77  cout<<"creating Populations"<<endl;
78  populations.push_back(new AnnealEvoPopulation(populationSize,myconfigdataaa));
79  }
80 
81  // Overwrite the random parameters based on data
82  if(seeded) // Test that the file exists
83  {
84  for(int i = 0; i < numberOfControllers; i++)
85  {
86  AnnealEvoMember* seededPop = populations[i]->controllers.back();
87  stringstream ss;
88  ss<<"logs/bestParameters-"<<this->suffix<<"-"<<i<<".nnw";
89  seededPop->loadFromFile(ss.str().c_str());
90  }
91  }
92  if(learning)
93  {
94  evolutionLog.open(("logs/evolution"+suffix+".csv").c_str(),ios::out);
95  }
96 }
97 
98 AnnealEvolution::~AnnealEvolution()
99 {
100  // @todo - solve the invalid pointer that occurs here
101  #if (0)
102  for(std::size_t i = 0; i < populations.size(); i++)
103  {
104  delete populations[i];
105  }
106  populations.clear();
107  #endif
108 }
109 
110 void AnnealEvolution::mutateEveryController()
111 {
112  for(int i=0;i<populations.size();i++)
113  {
114  populations.at(i)->mutate(&eng,numberOfElementsToMutate, Temp);
115  }
116 }
117 
118 
119 
120 void AnnealEvolution::orderAllPopulations()
121 {
122  generationNumber++;
123  double aveScore1 = 0.0;
124  double aveScore2 = 0.0;
125 #if (0)
126  // Disable definition of unused variables to suppress compiler warning
127  double maxScore1,maxScore2;
128 #endif
129  for(int i=0;i<scoresOfTheGeneration.size();i++)
130  {
131  aveScore1+=scoresOfTheGeneration[i][0];
132  aveScore2+=scoresOfTheGeneration[i][1];
133  }
134  aveScore1 /= scoresOfTheGeneration.size();
135  aveScore2 /= scoresOfTheGeneration.size();
136 
137 
138  for(int i=0;i<populations.size();i++)
139  {
140  populations.at(i)->orderPopulation();
141  }
142  evolutionLog<<generationNumber*numberOfTestsBetweenGenerations<<","<<aveScore1<<","<<aveScore2<<",";
143  evolutionLog<<populations.at(0)->getMember(0)->maxScore<<","<<populations.at(0)->getMember(0)->maxScore1<<","<<populations.at(0)->getMember(0)->maxScore2<<endl;
144 
145 
146  // what if member at 0 isn't the best of all time for some reason?
147  // This seems biased towards average scores
148  ofstream logfileLeader;
149  for(int i=0;i<populations.size();i++)
150  {
151  stringstream ss;
152  ss<<"logs/bestParameters-"<<suffix<<"-"<<i<<".nnw";
153 
154  populations[i]->getMember(0)->saveToFile(ss.str().c_str());
155  }
156 }
157 
158 double diffclock(clock_t clock1,clock_t clock2)
159 {
160  double diffticks=clock1-clock2;
161  double diffms=(diffticks*10)/CLOCKS_PER_SEC;
162  return diffms;
163 }
164 
165 vector <AnnealEvoMember *> AnnealEvolution::nextSetOfControllers()
166 {
167  int testsToDo=0;
168  if(coevolution)
169  testsToDo=numberOfTestsBetweenGenerations; //stop when we reach x amount of random tests
170  else
171  testsToDo=populationSize; //stop when we test each element once
172 
173  if(currentTest == testsToDo)
174  {
175  orderAllPopulations();
176  mutateEveryController();
177  Temp -= 0.0; // @todo - make this a parameter
178  cout<<"mutated the populations"<<endl;
179  this->scoresOfTheGeneration.clear();
180 
181  if(coevolution)
182  currentTest=0;//Start from 0
183  else
184  currentTest=populationSize-numberOfElementsToMutate; //start from the mutated ones only (last x)
185  }
186 
187  selectedControllers.clear();
188  for(int i=0;i<populations.size();i++)
189  {
190  int selectedOne=0;
191  if(coevolution)
192  selectedOne=rand()%populationSize; //select random one from each pool
193  else
194  selectedOne=currentTest; //select the same from each pool
195 
196 // cout<<"selected: "<<selectedOne<<endl;
197  selectedControllers.push_back(populations.at(i)->getMember(selectedOne));
198  }
199  currentTest++;
200 // cout<<"currentTest:"<<currentTest<<endl;
201 
202  return selectedControllers;
203 }
204 
205 void AnnealEvolution::updateScores(vector <double> multiscore)
206 {
207  if(multiscore.size()==2)
208  this->scoresOfTheGeneration.push_back(multiscore);
209  else
210  multiscore.push_back(-1.0);
211  double score=1.0* multiscore[0] - 0.0 * multiscore[1];
212 
213  //Record it to the file
214  ofstream payloadLog;
215  payloadLog.open("logs/scores.csv",ios::app);
216  payloadLog<<multiscore[0]<<","<<multiscore[1];
217 
218  for(int oneElem=0;oneElem<selectedControllers.size();oneElem++)
219  {
220  AnnealEvoMember * controllerPointer=selectedControllers.at(oneElem);
221 
222  controllerPointer->pastScores.push_back(score);
223  double prevScore=controllerPointer->maxScore;
224  if(prevScore>score)
225  {
226  double newScore= leniencyCoef * prevScore + (1.0 - leniencyCoef) * score;
227  controllerPointer->maxScore=newScore;
228  }
229  else
230  {
231  controllerPointer->maxScore=score;
232  controllerPointer->maxScore1=multiscore[0];
233  controllerPointer->maxScore2=multiscore[1];
234  }
235  std::size_t n = controllerPointer->statelessParameters.size();
236  for (std::size_t i = 0; i < n; i++)
237  {
238  payloadLog << "," << controllerPointer->statelessParameters[i];
239  }
240  }
241 
242  payloadLog<<endl;
243  payloadLog.close();
244  return;
245 }
A class to read a learning configuration from a .ini file.
Contains the definition of class AnnealEvolution. Adapting NeuroEvolution to do Simulated Annealing...