Grid.h
Go to the documentation of this file.
1 /*!
2  * \brief
3  *
4  * \author T.Voss
5  * \date 2011
6  *
7  *
8  * \par Copyright 1995-2017 Shark Development Team
9  *
10  * <BR><HR>
11  * This file is part of Shark.
12  * <http://shark-ml.org/>
13  *
14  * Shark is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU Lesser General Public License as published
16  * by the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * Shark is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public License
25  * along with Shark. If not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28 #ifndef SHARK_EA_GRID_H
29 #define SHARK_EA_GRID_H
30 
31 #include <map>
32 #include <vector>
33 
34 namespace shark {
35  /** \cond */
36  class AdaptiveGrid {
37  public:
38  struct Hypercube {
39  Hypercube() : m_size( 0. ),
40  m_noSolutions( 0 ),
41  m_isOccupied( false ) {
42  }
43 
44  double m_size;
45  unsigned int m_noSolutions;
46  bool m_isOccupied;
47  };
48 
49  typedef std::map< std::size_t, Hypercube >::iterator iterator;
50  typedef std::map< std::size_t, Hypercube >::const_iterator const_iterator;
51 
52  std::map< std::size_t, Hypercube > m_denseGrid;
53  iterator m_mostOccupiedHypercube;
54 
55  /**
56  * Number of bi-divisions of the objective space
57  */
58  unsigned int m_noBisections;
59 
60  /**
61  *
62  * Grid lower bounds
63  */
64  RealVector m_lowerBounds;
65 
66  /**
67  * Grid upper bounds
68  */
69  RealVector m_upperBounds;
70 
71  /************************************************************************/
72  /* Extens of the grid */
73  /************************************************************************/
74  RealVector m_extents;
75 
76  /**
77  * Constructor.
78  * Creates an instance of AdaptativeGrid.
79  * @param noBisections Number of bi-divisions of the objective space.
80  * @param nObjetives Number of objectives of the problem.
81  */
82  AdaptiveGrid( unsigned int noBisections = 0, unsigned int noObjectives = 0 ) {
83  reset( noBisections, noObjectives );
84  } //AdaptativeGrid
85 
86  void reset( unsigned int noBisections, unsigned int noObjectives ) {
87  m_noBisections = noBisections;
88 
89  m_lowerBounds = RealVector( noObjectives, std::numeric_limits<double>::max() );
90  m_upperBounds = RealVector( noObjectives, -std::numeric_limits<double>::max() );
91 
92  m_extents = RealVector( noObjectives, 0 );
93 
94  // m_denseGrid = std::vector< Hypercube >( static_cast<std::size_t>( ::pow( 2., noBisections * noObjectives ) ) );
95  m_denseGrid.clear();
96  m_mostOccupiedHypercube = m_denseGrid.end();
97  }
98 
99  /**
100  * Updates the grid limits considering the solutions contained in a
101  * <code>SolutionSet</code>.
102  * @param solutionSet The <code>SolutionSet</code> considered.
103  */
104  template<typename Set>
105  void updateLimits( const Set & solutionSet ) {
106 
107  m_lowerBounds = RealVector( m_lowerBounds.size(), std::numeric_limits<double>::max() );
108  m_upperBounds = RealVector( m_lowerBounds.size(), -std::numeric_limits<double>::max() );
109 
110  typename Set::const_iterator it;
111  for( it = solutionSet.begin(); it != solutionSet.end(); ++it ) {
112 
113  for( unsigned int i = 0; i < it->fitness( shark::tag::PenalizedFitness() ).size(); i++ ) {
114  m_lowerBounds( i ) = std::min( m_lowerBounds( i ), it->fitness( shark::tag::PenalizedFitness() )[i] );
115  m_upperBounds( i ) = std::max( m_upperBounds( i ), it->fitness( shark::tag::PenalizedFitness() )[i] );
116  }
117  }
118  m_extents = m_upperBounds - m_lowerBounds;
119  } //updateLimits
120 
121  /**
122  * Updates the grid adding solutions contained in a specific
123  * <code>SolutionSet</code>.
124  * <b>REQUIRE</b> The grid limits must have been previously calculated.
125  * @param solutionSet The <code>SolutionSet</code> considered.
126  */
127  template<typename Set>
128  void addSolutionSet( const Set & solutionSet) {
129  m_mostOccupiedHypercube = m_denseGrid.begin();
130  int itt;
131  typename Set::const_iterator it;
132  for( it = solutionSet.begin(); it != solutionSet.end(); ++it ) {
133  itt = location( *it );
134 
135  if( itt == -1 )
136  throw( shark::Exception( "AdaptiveGrid::addSolutionSet: The grid limits need to be calculated before." ) );
137 
138  /*itt->second.m_noSolutions++;
139  if( m_mostOccupiedHypercube->second.m_noSolutions > itt->second.m_noSolutions )
140  std::swap( m_mostOccupiedHypercube, itt );*/
141  addSolution( itt );
142  } // for
143 
144  //The grid has been updated, so also update ocuppied's hypercubes
145  // calculateOccupied();
146  }
147 
148 
149  /**
150  * Updates the grid limits and the grid content adding the solutions contained
151  * in a specific <code>SolutionSet</code>.
152  * @param solutionSet The <code>SolutionSet</code>.
153  */
154  template<typename Set>
155  void updateGrid( const Set & solutionSet ){
156 
157  //Update lower and upper limits
158  updateLimits( solutionSet );
159 
160  m_denseGrid.clear();
161  m_mostOccupiedHypercube = m_denseGrid.end();
162 
163  //Add the population
164  addSolutionSet(solutionSet);
165  } //updateGrid
166 
167 
168  /**
169  * Updates the grid limits and the grid content adding a new
170  * <code>Solution</code>.
171  * If the solution falls out of the grid bounds, the limits and content of the
172  * grid must be re-calculated.
173  * @param solution <code>Solution</code> considered to update the grid.
174  * @param solutionSet <code>SolutionSet</code> used to update the grid.
175  */
176  template<typename Solution, typename Set>
177  void updateGrid( const Solution & solution, const Set & solutionSet ) {
178 
179  int it = location( solution );
180  if ( it == -1 ) {
181  //Update lower and upper limits
182  updateLimits( solutionSet );
183 
184  //Actualize the lower and upper limits whit the individual
185  for( std::size_t i = 0; i < solution.fitness( shark::tag::PenalizedFitness() ).size(); i++ ){
186  m_lowerBounds( i ) = std::min( m_lowerBounds( i ), solution.fitness( shark::tag::PenalizedFitness() )[i] );
187  m_upperBounds( i ) = std::max( m_upperBounds( i ), solution.fitness( shark::tag::PenalizedFitness() )[i] );
188  } // for
189 
190  m_extents = m_upperBounds - m_lowerBounds;
191 
192  m_denseGrid.clear();
193  m_mostOccupiedHypercube = m_denseGrid.end();
194 
195  //add the population
196  addSolutionSet(solutionSet);
197  } // if
198  } //updateGrid
199 
200 
201  /**
202  * Calculates the hypercube of a solution.
203  * @param solution The <code>Solution</code>.
204  */
205  template<typename Solution>
206  int location( const Solution & solution ) const {
207  //Create a int [] to store the range of each objective
208  std::vector< std::size_t > positions( solution.fitness( shark::tag::PenalizedFitness() ).size(), 0 );
209 
210  //Calculate the position for each objective
211  for( std::size_t obj = 0; obj < solution.fitness( shark::tag::PenalizedFitness() ).size(); obj++ ) {
212 
213  if( solution.fitness( shark::tag::PenalizedFitness() )[ obj ] > m_upperBounds( obj ) )
214  return( -1 );
215  if( solution.fitness( shark::tag::PenalizedFitness() )[ obj ] < m_lowerBounds( obj ) )
216  return( -1 );
217 
218  if( solution.fitness( shark::tag::PenalizedFitness() )[ obj ] == m_lowerBounds[obj] ) {
219  positions[ obj ] = 0;
220  continue;
221  }
222 
223  if( solution.fitness( shark::tag::PenalizedFitness() )[ obj ] == m_upperBounds[ obj ] ) {
224  positions[obj] = static_cast<std::size_t>( (::pow( 2.0, static_cast<double>( m_noBisections ) ) )-1 );
225  continue;
226  }
227 
228 
229  double tmpSize = m_extents( obj );
230  double value = solution.fitness( shark::tag::PenalizedFitness() )[ obj ];
231  double account = m_lowerBounds( obj );
232  std::size_t ranges = static_cast<std::size_t>( (::pow( 2.0, static_cast<double>( m_noBisections ) ) ) );
233 
234  for( unsigned int b = 0; b < m_noBisections; b++ ) {
235  tmpSize /= 2.0;
236  ranges /= 2;
237  if( value > (account + tmpSize) ) {
238  positions[ obj ] += ranges;
239  account += tmpSize;
240  }
241  }
242  }
243 
244  //Calculate the location into the hypercubes
245  std::size_t location = 0;
246  for( unsigned int obj = 0; obj < solution.fitness( shark::tag::PenalizedFitness() ).size(); obj++ ) {
247  location += positions[obj] * static_cast<std::size_t>( (::pow( 2.0, obj * static_cast<double>( m_noBisections ) ) ) );
248  }
249  return( location );
250  } //location
251 
252  /**
253  * Returns the value of the most populated hypercube.
254  * @return The hypercube with the maximum number of solutions.
255  */
256  iterator mostPopulated() {
257  return( m_mostOccupiedHypercube );
258  } // getMostPopulated
259 
260  /**
261  * Returns the number of solutions into a specific hypercube.
262  * @param idx Number of the hypercube.
263  * @return The number of solutions into a specific hypercube.
264  */
265  unsigned int locationDensity( std::size_t idx ) {
266  iterator it = m_denseGrid.find( idx );
267  if( it == m_denseGrid.end() )
268  return( 0 );
269  return( it->second.m_noSolutions );
270  } //getLocationDensity
271 
272  /**
273  * Decreases the number of solutions into a specific hypercube.
274  * @param location Number of hypercube.
275  */
276  int removeSolution( std::size_t location ) {
277  iterator it = m_denseGrid.find( location );
278  if( it == m_denseGrid.end() ) //TODO: Throw exception here?
279  return( -1 );
280  //Decrease the solutions in the location specified.
281  it->second.m_noSolutions--;
282 
283  if( m_mostOccupiedHypercube == it )
284  for( iterator itt = m_denseGrid.begin(); itt != m_denseGrid.end(); ++itt )
285  if( itt->second.m_noSolutions > m_mostOccupiedHypercube->second.m_noSolutions )
286  m_mostOccupiedHypercube = itt;
287 
288  //If hypercubes[location] now becomes to zero, then update ocupped hypercubes
289  if( it->second.m_noSolutions == 0 ) {
290  m_denseGrid.erase( it );
291  calculateOccupied();
292 
293  return( 0 );
294  }
295  return( it->second.m_noSolutions );
296  } //removeSolution
297 
298  /**
299  * Increases the number of solutions into a specific hypercube.
300  * @param location Number of hypercube.
301  */
302  void addSolution( std::size_t location ) {
303  Hypercube & h = m_denseGrid[location];
304  h.m_noSolutions++;
305 
306  if( m_mostOccupiedHypercube != m_denseGrid.end() ) {
307  if( h.m_noSolutions > m_mostOccupiedHypercube->second.m_noSolutions ) {
308  m_mostOccupiedHypercube = m_denseGrid.find( location );
309  }
310  } else
311  m_mostOccupiedHypercube = m_denseGrid.find( location );
312 
313  //if hypercubes[location] becomes to one, then recalculate
314  //the occupied hypercubes
315  if( h.m_noSolutions == 1 )
316  calculateOccupied();
317  } //addSolution
318 
319  /**
320  * Returns the number of bi-divisions performed in each objective.
321  * @return the number of bi-divisions.
322  */
323  unsigned int noBisections() {
324  return( m_noBisections );
325  } //getBisections
326 
327  /**
328  * Returns a random hypercube using a rouleteWheel method.
329  * @return the number of the selected hypercube.
330  */
331  // public int rouletteWheel(){
332  // //Calculate the inverse sum
333  // double inverseSum = 0.0;
334  // for (int i = 0; i < hypercubes_.length; i++) {
335  // if (hypercubes_[i] > 0) {
336  // inverseSum += 1.0 / (double)hypercubes_[i];
337  // }
338  // }
339  //
340  // //Calculate a random value between 0 and sumaInversa
341  // double random = PseudoRandom.randDouble(0.0,inverseSum);
342  // int hypercube = 0;
343  // double accumulatedSum = 0.0;
344  // while (hypercube < hypercubes_.length){
345  // if (hypercubes_[hypercube] > 0) {
346  // accumulatedSum += 1.0 / (double)hypercubes_[hypercube];
347  // } // if
348  //
349  // if (accumulatedSum > random) {
350  // return hypercube;
351  // } // if
352  //
353  // hypercube++;
354  // } // while
355  //
356  // return hypercube;
357  // } //rouletteWheel
358 
359  /**
360  * Calculates the number of hypercubes having one or more solutions.
361  * return the number of hypercubes with more than zero solutions.
362  */
363  std::size_t calculateOccupied() {
364  return( m_denseGrid.size() );
365  } //calculateOcuppied
366 
367  /**
368  * Returns the number of hypercubes with more than zero solutions.
369  * @return the number of hypercubes with more than zero solutions.
370  */
371  std::size_t occupiedHypercubes(){
372  return( m_denseGrid.size() );
373  } // occupiedHypercubes
374 
375 
376  /**
377  * Returns a random hypercube that has more than zero solutions.
378  * @return The hypercube.
379  */
380 // iterator randomOccupiedHypercube(){
381 // return( m_denseGrid.begin() + random::discrete( 0, m_denseGrid.size() ) );
382 // } //randomOccupiedHypercube
383  }; //AdaptativeGrid
384 }
385 
386 /** \endcond */
387 #endif