View Javadoc

1   /*
2   
3       dsh-evolve  Framework for evolutionary algorithms.
4       Copyright (c) 2005-2013 held jointly by the individual authors.
5   
6       This library is free software; you can redistribute it and/or modify it
7       under the terms of the GNU Lesser General Public License as published
8       by the Free Software Foundation; either version 3 of the License, or (at
9       your option) any later version.
10  
11      This library is distributed in the hope that it will be useful, but WITHOUT
12      ANY WARRANTY; with out even the implied warranty of MERCHANTABILITY or
13      FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14      License for more details.
15  
16      You should have received a copy of the GNU Lesser General Public License
17      along with this library;  if not, write to the Free Software Foundation,
18      Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
19  
20      > http://www.fsf.org/licensing/licenses/lgpl.html
21      > http://www.opensource.org/licenses/lgpl-license.php
22  
23  */
24  package org.dishevelled.evolve.impl;
25  
26  import java.util.ArrayList;
27  import java.util.Collection;
28  import java.util.Iterator;
29  
30  import javax.swing.event.EventListenerList;
31  
32  import org.dishevelled.evolve.EvolutionaryAlgorithm;
33  import org.dishevelled.evolve.EvolutionaryAlgorithmEvent;
34  import org.dishevelled.evolve.EvolutionaryAlgorithmListener;
35  import org.dishevelled.evolve.ExitStrategy;
36  import org.dishevelled.evolve.Fitness;
37  import org.dishevelled.evolve.Mutation;
38  import org.dishevelled.evolve.Recombination;
39  import org.dishevelled.evolve.Selection;
40  
41  import org.dishevelled.weighted.WeightedMap;
42  import org.dishevelled.weighted.HashWeightedMap;
43  
44  /**
45   * Implementation of an evolutionary algorithm function.
46   *
47   * @param <I> individual type
48   * @author  Michael Heuer
49   * @version $Revision: 320 $ $Date: 2007-10-23 14:06:38 -0500 (Tue, 23 Oct 2007) $
50   */
51  public final class EvolutionaryAlgorithmImpl<I>
52      implements EvolutionaryAlgorithm<I>
53  {
54      /** Default hash map load factor. */
55      private static final float DEFAULT_LOAD_FACTOR = 0.75f;
56  
57      /** Listener list. */
58      private EventListenerList listenerList = new EventListenerList();
59  
60  
61      /**
62       * Create a new evolutionary algorithm function implementation.
63       */
64      public EvolutionaryAlgorithmImpl()
65      {
66          // empty
67      }
68  
69  
70      /** {@inheritDoc} */
71      public Collection<I> evolve(final Collection<I> individuals,
72                                  final ExitStrategy<I> exitStrategy,
73                                  final Recombination<I> recombination,
74                                  final Mutation<I> mutation,
75                                  final Fitness<I> fitness,
76                                  final Selection<I> selection)
77      {
78          checkParameters(individuals, exitStrategy, recombination, mutation, fitness, selection);
79  
80          // initialize population with individuals
81          Collection<I> population = new ArrayList<I>(individuals);
82          // initialize fitness scores to 0.0d
83          WeightedMap<I> scores = new HashWeightedMap<I>(population.size(), DEFAULT_LOAD_FACTOR);
84          for (I i : individuals)
85          {
86              scores.put(i, Double.valueOf(0.0d));
87          }
88  
89          int time = 0;
90          while (!exitStrategy.evaluate(population, scores, time))
91          {
92              fireExitFailed(population, scores, time);
93  
94              // recombine population
95              Collection<I> recombined = recombination.recombine(population);
96              fireRecombined(population, recombined);
97  
98              // mutate amongst themselves
99              Collection<I> mutated = mutation.mutate(recombined);
100             fireMutated(recombined, mutated);
101 
102             // evalute fitness
103             for (I i : mutated)
104             {
105                 Double score = fitness.score(i);
106                 scores.put(i, score);
107                 fireFitnessCalculated(i, score);
108             }
109 
110             // select individuals for next generation
111             population = selection.select(mutated, scores);
112             fireSelected(mutated, population, scores);
113 
114             // remove last generation from scores
115             for (Iterator<I> keys = scores.keySet().iterator(); keys.hasNext(); )
116             {
117                 I i = keys.next();
118                 if (!population.contains(i))
119                 {
120                     keys.remove();
121                 }
122             }
123 
124             time++;
125         }
126 
127         // exit strategy condition(s) met, return successful population
128         fireExitSucceeded(population, scores, time);
129         return population;
130     }
131 
132 
133     /**
134      * Check that the specified parameters are valid.
135      *
136      * @param individuals collection of individuals, must not be null and must contain
137      *    at least one individual
138      * @param exitStrategy exit strategy function, must not be null
139      * @param recombination recombination function, must not be null
140      * @param mutation mutation function, must not be null
141      * @param fitness fitness function, must not be null
142      * @param selection selection function, must not be null
143      */
144     private void checkParameters(final Collection<I> individuals,
145                                  final ExitStrategy<I> exitStrategy,
146                                  final Recombination<I> recombination,
147                                  final Mutation<I> mutation,
148                                  final Fitness<I> fitness,
149                                  final Selection<I> selection)
150     {
151         // check for null or otherwise illegal parameters
152         if (individuals == null)
153         {
154             throw new IllegalArgumentException("individuals must not be null");
155         }
156         if (individuals.size() == 0)
157         {
158             throw new IllegalArgumentException("individuals must not be empty");
159         }
160         if (exitStrategy == null)
161         {
162             throw new IllegalArgumentException("exitStrategy must not be null");
163         }
164         if (recombination == null)
165         {
166             throw new IllegalArgumentException("recombination must not be null");
167         }
168         if (mutation == null)
169         {
170             throw new IllegalArgumentException("mutation must not be null");
171         }
172         if (fitness == null)
173         {
174             throw new IllegalArgumentException("fitness must not be null");
175         }
176         if (selection == null)
177         {
178             throw new IllegalArgumentException("selection must not be null");
179         }
180     }
181 
182    /**
183      * Add the specified evolutionary algorithm listener.
184      *
185      * @param l evolutionary algorithm listener to add
186      */
187     /** {@inheritDoc} */
188     public void addEvolutionaryAlgorithmListener(final EvolutionaryAlgorithmListener<I> l)
189     {
190         listenerList.add(EvolutionaryAlgorithmListener.class, l);
191     }
192 
193     /** {@inheritDoc} */
194     public void removeEvolutionaryAlgorithmListener(final EvolutionaryAlgorithmListener<I> l)
195     {
196         listenerList.remove(EvolutionaryAlgorithmListener.class, l);
197     }
198 
199     /** {@inheritDoc} */
200     public int getEvolutionaryAlgorithmListenerCount()
201     {
202         return listenerList.getListenerCount(EvolutionaryAlgorithmListener.class);
203     }
204 
205     /** {@inheritDoc} */
206     public EvolutionaryAlgorithmListener<I>[] getEvolutionaryAlgorithmListeners()
207     {
208         return (EvolutionaryAlgorithmListener<I>[]) listenerList.getListeners(EvolutionaryAlgorithmListener.class);
209     }
210 
211     /**
212      * Fire an exit failed event to all registered listeners.
213      *
214      * @param population population
215      * @param scores fitness scores
216      * @param time time
217      */
218     private void fireExitFailed(final Collection<I> population, final WeightedMap<I> scores, final int time)
219     {
220         Object[] listeners = listenerList.getListenerList();
221         EvolutionaryAlgorithmEvent<I> e = null;
222 
223         for (int i = listeners.length - 2; i >= 0; i -= 2)
224         {
225             if (listeners[i] == EvolutionaryAlgorithmListener.class)
226             {
227                 if (e == null)
228                 {
229                     e = new EvolutionaryAlgorithmEvent<I>(this, population, scores, time);
230                 }
231 
232                 ((EvolutionaryAlgorithmListener<I>) listeners[i + 1]).exitFailed(e);
233             }
234         }
235     }
236 
237     /**
238      * Fire an exit succeeded event to all registered listeners.
239      *
240      * @param population population
241      * @param scores fitness scores
242      * @param time time
243      */
244     private void fireExitSucceeded(final Collection<I> population, final WeightedMap<I> scores, final int time)
245     {
246         Object[] listeners = listenerList.getListenerList();
247         EvolutionaryAlgorithmEvent<I> e = null;
248 
249         for (int i = listeners.length - 2; i >= 0; i -= 2)
250         {
251             if (listeners[i] == EvolutionaryAlgorithmListener.class)
252             {
253                 if (e == null)
254                 {
255                     e = new EvolutionaryAlgorithmEvent<I>(this, population, scores, time);
256                 }
257 
258                 ((EvolutionaryAlgorithmListener<I>) listeners[i + 1]).exitSucceeded(e);
259             }
260         }
261     }
262 
263     /**
264      * Fire a recombined event to all registered listeners.
265      *
266      * @param population population
267      * @param recombined recombined
268      */
269     private void fireRecombined(final Collection<I> population, final Collection<I> recombined)
270     {
271         Object[] listeners = listenerList.getListenerList();
272         EvolutionaryAlgorithmEvent<I> e = null;
273 
274         for (int i = listeners.length - 2; i >= 0; i -= 2)
275         {
276             if (listeners[i] == EvolutionaryAlgorithmListener.class)
277             {
278                 if (e == null)
279                 {
280                     e = new EvolutionaryAlgorithmEvent<I>(this, population, recombined, (Collection<I>) null);
281                 }
282 
283                 ((EvolutionaryAlgorithmListener<I>) listeners[i + 1]).recombined(e);
284             }
285         }
286     }
287 
288     /**
289      * Fire a mutated event to all registered listeners.
290      *
291      * @param recombined recombined
292      * @param mutated mutated
293      */
294     private void fireMutated(final Collection<I> recombined, final Collection<I> mutated)
295     {
296         Object[] listeners = listenerList.getListenerList();
297         EvolutionaryAlgorithmEvent<I> e = null;
298 
299         for (int i = listeners.length - 2; i >= 0; i -= 2)
300         {
301             if (listeners[i] == EvolutionaryAlgorithmListener.class)
302             {
303                 if (e == null)
304                 {
305                     e = new EvolutionaryAlgorithmEvent<I>(this, null, recombined, mutated);
306                 }
307 
308                 ((EvolutionaryAlgorithmListener<I>) listeners[i + 1]).mutated(e);
309             }
310         }
311     }
312 
313     /**
314      * Fire a fitness calculated event to all registered listeners.
315      *
316      * @param individual individual
317      * @param score score
318      */
319     private void fireFitnessCalculated(final I individual, final Double score)
320     {
321         Object[] listeners = listenerList.getListenerList();
322         EvolutionaryAlgorithmEvent<I> e = null;
323 
324         for (int i = listeners.length - 2; i >= 0; i -= 2)
325         {
326             if (listeners[i] == EvolutionaryAlgorithmListener.class)
327             {
328                 if (e == null)
329                 {
330                     e = new EvolutionaryAlgorithmEvent<I>(this, individual, score);
331                 }
332 
333                 ((EvolutionaryAlgorithmListener<I>) listeners[i + 1]).fitnessCalculated(e);
334             }
335         }
336     }
337 
338     /**
339      * Fire a selected event to all registered listeners.
340      *
341      * @param population population
342      * @param selected selected
343      * @param scores fitness scores
344      */
345     private void fireSelected(final Collection<I> population,
346                               final Collection<I> selected,
347                               final WeightedMap<I> scores)
348     {
349         Object[] listeners = listenerList.getListenerList();
350         EvolutionaryAlgorithmEvent<I> e = null;
351 
352         for (int i = listeners.length - 2; i >= 0; i -= 2)
353         {
354             if (listeners[i] == EvolutionaryAlgorithmListener.class)
355             {
356                 if (e == null)
357                 {
358                     e = new EvolutionaryAlgorithmEvent<I>(this, population, selected, scores);
359                 }
360 
361                 ((EvolutionaryAlgorithmListener<I>) listeners[i + 1]).selected(e);
362             }
363         }
364     }
365 }