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 * <https://shark-ml.github.io/Shark/>
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
34namespace 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