GPLIB++
ParetoGA.cpp
Go to the documentation of this file.
1 #include "ParetoGA.h"
2 #include <iostream>
3 #include <algorithm>
4 #include <numeric>
5 #include "NumUtil.h"
6 #include <boost/algorithm/minmax_element.hpp>
7 #include <boost/numeric/ublas/io.hpp>
8 
9 using namespace std;
10 namespace gplib
11  {
12  //! Determines whether one vector of misfit values is partially less than the other
13  /*! This function object implements the concept of dominance used in NSGA-II and other
14  * pareto based optimization methods. The vector fit1 dominates fit2 (or is partially less)
15  * \f$ fit1 \prec_p fit2 \Leftrightarrow \forall i fit1_i \leq fit2_i \:\wedge\: \exists i: fit1_i < fit2_i \f$
16  */
17  class dominates
18  {
19  public:
20  bool operator()(const gplib::rvec &fit1, const gplib::rvec &fit2) const
21  {
22  typedef vector<double>::const_iterator tit;
23  bool smaller = false;
24  const size_t length = fit2.size();
25  for (size_t i = 0; i < length; ++i)
26  {
27  if (fit1(i) > fit2(i))
28  return false;
29  if (fit1(i) < fit2(i))
30  smaller = true;
31  }
32  return smaller;
33  }
34  };
35 
36  void ParetoGA::CalcCrowdingDistance(gplib::rmat &LocalMisFit,
37  GeneralPopulation &LocalPopulation)
38  {
39  const double NearInfinity = 1e50;
40  const double tolerance = 1e-10;
41  const unsigned int popsize = LocalPopulation.GetPopsize();
42 
43  tcrowddistv CrowdingDistances(popsize);
44  for (unsigned int i = 0; i < popsize; ++i)
45  CrowdingDistances(i) = 0;
46  for (unsigned int i = 0; i < nobjective; ++i)
47  {
48  if (fcmp(GetWeights().at(i), 0, tolerance) != 0)
49  {
50  pair<tMisfitIterator, tMisfitIterator> MinMax =
51  boost::minmax_element(ublas::row(LocalMisFit, i).begin(),
52  ublas::row(LocalMisFit, i).end());
53  double normalize = 1;
54  if (fcmp(*(MinMax.second) - *(MinMax.first), 0, tolerance)
55  != 0) // if minimum not equal maximum
56  normalize = *(MinMax.second) - *(MinMax.first);
57  for (unsigned int j = 0; j < Ranks.size(); ++j)
58  {
59  tIndexMap IndexMap;
60  for (unsigned int k = 0; k < Ranks.at(j).size(); ++k)
61  {
62  IndexMap.insert(make_pair(LocalMisFit(i,
63  Ranks.at(j).at(k)), Ranks.at(j).at(k)));
64  }
65  tIndexMap::iterator end = --IndexMap.end();
66  tIndexMap::iterator pos = IndexMap.begin();
67  CrowdingDistances(pos->second) = NearInfinity; // set the crowding distance very large
68  if (pos != end)
69  {
70  CrowdingDistances(end->second) = NearInfinity; // for first and last element
71  tIndexMap::iterator previous = IndexMap.begin(); //the previous element is the first element
72  tIndexMap::iterator next = pos; // we start at the second, not the first element
73  advance(pos, 1);
74  advance(next, 2);
75  for (; pos != end; pos++)
76  {
77  CrowdingDistances(pos->second) += (next->first
78  - previous->first) / normalize;
79  ++previous;
80  ++next;
81  }
82  }
83  }
84  }
85  }
86  LocalPopulation.SetCrowdingDistances(CrowdingDistances);
87  }
88 
89  void ParetoGA::CalcProbabilities(const int iterationnumber,
90  gplib::rmat &LocalMisFit, GeneralPopulation &LocalPopulation)
91  {
92  const unsigned int size = LocalPopulation.GetPopsize();
93  gplib::rvec currmisfit(nobjective), compmisfit(nobjective); //local storage
94  vector<int> Indices;
95  unsigned int rankedelements = 0;
96 
97  vector<int> CurrRanks; //the indices of the members in the current rank
98  unsigned int i, j, k = 0;
99  vector<bool> dominated(size, false); //for each member whether it is dominated
100  unsigned int maxindex = size; //the maximum index in the beginning is the population size
101 
102  if (!Ranks.empty()) //empty old storage
103  Ranks.clear();
104  Indices.reserve(size); //intialize population index
105  for (i = 0; i < size; ++i)
106  Indices.push_back(i);
107  while (rankedelements < size) // while we haven't ranked everything
108  {
109  CurrRanks.clear(); //empty the current rank
110  for (i = 0; i < maxindex; ++i) // for all population members that haven't been ranked
111  {
112  for (j = 0; j < nobjective; ++j) //get the misfit values
113  currmisfit(j) = LocalMisFit(j, Indices.at(i));
114  j = 0;
115  dominated.at(i) = false; // assume it is not dominated
116  while (!dominated.at(i) && (j < maxindex)) //while we haven't found it dominated or reached the maximum index
117  {
118  for (k = 0; k < nobjective; ++k)
119  compmisfit(k) = LocalMisFit(k, Indices.at(j)); //get the misfit values for comparison
120  if (dominates()(compmisfit, currmisfit)) //if current member is dominated
121  {
122  dominated.at(i) = true; // set domination property in vector
123  }
124  ++j;
125  }
126  } //end for all population members that haven't been ranked
127 
128  for (i = 0; i < maxindex; ++i) //remove non dominated members from comparison
129  {
130  if (!dominated.at(i)) //if the current member is not dominated
131  {
132  CurrRanks.push_back(Indices.at(i)); // add it to the non-dominated front
133  Indices.at(i) = Indices.at(maxindex - 1); //copy the last active index in the current position
134  dominated.at(i) = dominated.at(maxindex - 1); // same with domination property
135  ++rankedelements;//we have now ranked one element
136  --maxindex; // and have one less to go, the previous last index is now copied
137  --i; // we have to examine the element in this position again, because we copied
138  }
139  }
140  Ranks.push_back(CurrRanks); //add current rank to overall ranks
141  } //now we have ranked everything
142  const unsigned int nranks = Ranks.size();
143  cout << "NRanks : " << nranks << endl;
144  double sum = 0.0; //now we calculate the probabilities
145  double prob = 0.0;
146  tprobabilityv Probabilities(LocalPopulation.GetPopsize()); //allocate an array
147  for (i = 0; i < nranks; ++i) //for all ranks
148  {
149  for (j = 0; j < Ranks.at(i).size(); ++j) //and members in the rank
150  {
151  prob = nranks - i; //high rank is low probability
152  Probabilities(Ranks.at(i).at(j)) = prob; //Assign to the right member
153  sum += prob; //sum for normalization
154  }
155  }
156  Probabilities /= sum; //make values probabilities
157  LocalPopulation.SetProbabilities(Probabilities); //assign to population object
158 
159  CalcCrowdingDistance(LocalMisFit, LocalPopulation);
160  }
161 
162  void ParetoGA::Elitism(const int iterationnumber)
163  {
164  const unsigned int popsize = Population->GetPopsize();
165  const unsigned int ngenes = Population->GetGenesize();
166  GeneralPopulation IntermediatePop(Population->GetPopulation(),
167  Population->GetOldPopulation());
168  gplib::rmat IntermediateMisFit(nobjective, 2 * popsize);
169  ublas::matrix_range<gplib::rmat> MisFitFirstHalf(IntermediateMisFit,
170  ublas::range(0, nobjective), ublas::range(0, popsize));
171  ublas::matrix_range<gplib::rmat> MisFitSecondHalf(IntermediateMisFit,
172  ublas::range(0, nobjective), ublas::range(popsize, 2 * popsize));
173  MisFitFirstHalf = MisFit;
174  MisFitSecondHalf = OldMisFit;
175  CalcProbabilities(iterationnumber, IntermediateMisFit, IntermediatePop);
176 
177  unsigned int included = 0;
178  unsigned int currentrank = 0;
179  tpopulation Newpopulation(popsize, ngenes);
180  while (Ranks.at(currentrank).size() <= (popsize - included)) // as long as we can fit the current rank into the population
181  {
182  for (unsigned int j = 0; j < Ranks.at(currentrank).size(); ++j)
183  {
184  ublas::row(Newpopulation, included) = ublas::row(
185  IntermediatePop.GetPopulation(),
186  Ranks.at(currentrank).at(j));
187  ++included;
188  }
189  ++currentrank;
190  }
191  //Now we have to fill up the rest sorted by distance
192  tIndexMap IndexMap; //sorts the current rank by crowding distance and stores the associated index
193  for (unsigned int j = 0; j < Ranks.at(currentrank).size(); ++j)
194  IndexMap.insert(make_pair(IntermediatePop.GetCrowdingDistances()(
195  Ranks.at(currentrank).at(j)), Ranks.at(currentrank).at(j)));
196  tIndexMap::iterator pos = IndexMap.begin();
197  advance(pos, Ranks.at(currentrank).size() - (popsize - included)); // we have to take the last members with the biggest distance
198  while (pos != IndexMap.end())
199  {
200  ublas::row(Newpopulation, included) = ublas::row(
201  IntermediatePop.GetPopulation(), pos->second);
202  ++included;
203  ++pos;
204  }
205  Population->SetPopulation(Newpopulation);
206  }
207 
208  void ParetoGA::PrintRanks(std::ostream &output)
209  {
210  const unsigned int nobj = MisFit.size1();
211  const unsigned int nranks = Ranks.size();
212  for (unsigned int i = 0; i < nranks; ++i)
213  {
214  output << "Rank: " << i << endl;
215  for (unsigned int j = 0; j < Ranks.at(i).size(); ++j)
216  {
217  for (unsigned int k = 0; k < nobj; ++k)
218  output << MisFit(k, Ranks.at(i).at(j)) << " ";
219  output << endl;
220  }
221  output << endl;
222  }
223  output << endl;
224  }
225 
226  void ParetoGA::PrintFront(std::ostream &output)
227  {
228  const unsigned int nobj = MisFit.size1();
229  const unsigned int frontsize = Ranks.front().size();
230  for (unsigned int i = 0; i < frontsize; ++i)
231  {
232  for (unsigned int j = 0; j < nobj; ++j)
233  output << MisFit(j, Ranks.front().at(i)) << " ";
234  output << endl;
235  }
236  output << endl << endl;
237  }
238 
239  ParetoGA::~ParetoGA()
240  {
241  }
242  }
243 
The base class for the population of a genetic algorithm, implements storage and access functions...
ublas::vector< double > tprobabilityv
Definition: gentypes.h:17
void SetProbabilities(const tprobabilityv &LocalProb)
bool operator()(const gplib::rvec &fit1, const gplib::rvec &fit2) const
Definition: ParetoGA.cpp:20
gplib::rmat tpopulation
Definition: gentypes.h:25
Determines whether one vector of misfit values is partially less than the other.
Definition: ParetoGA.cpp:17
const int size
Definition: perftest.cpp:14
std::multimap< double, int > tIndexMap
Definition: gentypes.h:28
ublas::vector< double > tcrowddistv
Definition: gentypes.h:20