001    /*
002     * Copyright 2011 Christian Kumpe http://kumpe.de/christian/java
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *     http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package de.kumpe.hadooptimizer;
017    
018    import org.apache.commons.math.random.RandomGenerator;
019    
020    /**
021     * The base class of configurations for evolutionary algorithms based
022     * {@link Optimizer optimizers}.
023     * <p>
024     * It contains some of the main components for the evolution cycle of an
025     * evolutionary algorithm:
026     * <ul>
027     * <li>The {@link Halter} to {@link Halter#halt(java.util.Collection) check} if
028     * the evolution cycle has terminated.
029     * <li>The {@link Mutator} to {@link Mutator#mutate(Object) mutate} the
030     * children.
031     * <li>The {@link Evaluator} to {@link Evaluator#evaluate(Object) evaluate} the
032     * mutants.
033     * <li>The {@link #setPreserveParents(boolean) flag} to indicate if the parents
034     * should be merged with the newly created and evaluated individuals of the
035     * current generation.
036     * <li>The number of {@link #getParents() parents} that will be selected for the
037     * next generation.
038     * </ul>
039     * 
040     * @param <I>
041     *            the individuals' type
042     * 
043     * @author <a href="http://kumpe.de/christian/java">Christian Kumpe</a>
044     */
045    public abstract class EaOptimizerConfigurationBase<I> extends
046                    OptimizerConfiguration<I> {
047            private static final long serialVersionUID = 1L;
048    
049            private Halter<I> halter;
050            private Mutator<I> mutator;
051            private Evaluator<I> evaluator;
052            private int parents = 1;
053            private boolean preserveParents;
054    
055            /**
056             * {@inheritDoc}
057             * <p>
058             * Additionally calls
059             * {@link #injectRandomGenerator(Object, RandomGenerator)} on the given
060             * {@link #setHalter(Halter) halter}, {@link #setMutator(Mutator) mutator}
061             * and {@link #setEvaluator(Evaluator) evaluator}.
062             */
063            @Override
064            public void injectRandomGenerator(final RandomGenerator randomGenerator) {
065                    super.injectRandomGenerator(randomGenerator);
066    
067                    injectRandomGenerator(halter, randomGenerator);
068                    injectRandomGenerator(mutator, randomGenerator);
069                    injectRandomGenerator(evaluator, randomGenerator);
070            }
071    
072            /**
073             * {@inheritDoc}
074             * <p>
075             * Additionally verifies that a {@link #setHalter(Halter) halter},
076             * {@link #setMutator(Mutator) mutator} and {@link #setEvaluator(Evaluator)
077             * evaluator} has been set.
078             * 
079             * @throws IllegalStateException
080             *             {@inheritDoc}
081             */
082            @Override
083            public void validate() {
084                    super.validate();
085    
086                    if (null == halter) {
087                            throw new IllegalStateException(
088                                            "A Halter has to be set in the configuration.");
089                    }
090                    if (null == mutator) {
091                            throw new IllegalStateException(
092                                            "A Mutator has to be set in the configuration.");
093                    }
094                    if (null == evaluator) {
095                            throw new IllegalStateException(
096                                            "A Evaluator has to be set in the configuration.");
097                    }
098            }
099    
100            /**
101             * @return the configured {@link Halter}; <code>null</code> if none has been
102             *         set
103             */
104            public final Halter<I> getHalter() {
105                    return halter;
106            }
107    
108            /**
109             * @param halter
110             *            the {@link Halter} for this configuration
111             * 
112             * @throws NullPointerException
113             *             if {@code halter} is <code>null</code>
114             */
115            public final void setHalter(final Halter<I> halter) {
116                    if (null == halter) {
117                            throw new NullPointerException("halter may not be null.");
118                    }
119    
120                    this.halter = halter;
121            }
122    
123            /**
124             * @return the configured {@link Mutator}; <code>null</code> if none has
125             *         been set
126             */
127            public final Mutator<I> getMutator() {
128                    return mutator;
129            }
130    
131            /**
132             * @param mutator
133             *            the {@link Mutator} for this configuration
134             * 
135             * @throws NullPointerException
136             *             if {@code mutator} is <code>null</code>
137             */
138            public final void setMutator(final Mutator<I> mutator) {
139                    if (null == mutator) {
140                            throw new NullPointerException("mutator may not be null.");
141                    }
142    
143                    this.mutator = mutator;
144            }
145    
146            /**
147             * @return the configured {@link Evaluator}; <code>null</code> if none has
148             *         been set
149             */
150            public final Evaluator<I> getEvaluator() {
151                    return evaluator;
152            }
153    
154            /**
155             * @param evaluator
156             *            the {@link Evaluator} for this configuration
157             * 
158             * @throws NullPointerException
159             *             if {@code evaluator} is <code>null</code>
160             */
161            public final void setEvaluator(final Evaluator<I> evaluator) {
162                    if (null == evaluator) {
163                            throw new NullPointerException("evaluator may not be null.");
164                    }
165    
166                    this.evaluator = evaluator;
167            }
168    
169            /**
170             * @return the configured number of parents
171             * @see #setParents(int)
172             */
173            public final int getParents() {
174                    assert 0 < parents;
175    
176                    return parents;
177            }
178    
179            /**
180             * Sets the number of parents in the evolution cycle.
181             * <p>
182             * For an E(μ+/,λ)-evolution strategy, this would sets μ.
183             * <p>
184             * The default-value is {@code 1}.
185             * 
186             * @param parents
187             *            the number of parents
188             * 
189             * @throws IllegalArgumentException
190             *             if {@code parents} is zero or negative
191             */
192            public final void setParents(final int parents) {
193                    if (0 >= parents) {
194                            throw new IllegalArgumentException(
195                                            "parents must be greater than zero");
196                    }
197    
198                    this.parents = parents;
199            }
200    
201            /**
202             * @return <code>true</code> if parents will be preserved in the next
203             *         evolution cycle; <code>false</code> if parents will be discarded
204             */
205            public final boolean isPreserveParents() {
206                    return preserveParents;
207            }
208    
209            /**
210             * @param preserveParents
211             *            <code>true</code> if parents should be preserved in the next
212             *            evolution cycle; <code>false</code> if parents should be
213             *            discarded
214             */
215            public final void setPreserveParents(final boolean preserveParents) {
216                    this.preserveParents = preserveParents;
217            }
218    
219            @Override
220            public int hashCode() {
221                    final int prime = 31;
222                    int result = super.hashCode();
223                    result = prime * result
224                                    + (evaluator == null ? 0 : evaluator.hashCode());
225                    result = prime * result + (halter == null ? 0 : halter.hashCode());
226                    result = prime * result + (mutator == null ? 0 : mutator.hashCode());
227                    result = prime * result + parents;
228                    result = prime * result + (preserveParents ? 1231 : 1237);
229                    return result;
230            }
231    
232            @Override
233            public boolean equals(final Object obj) {
234                    if (this == obj) {
235                            return true;
236                    }
237                    if (!super.equals(obj)) {
238                            return false;
239                    }
240                    if (!(obj instanceof EaOptimizerConfigurationBase)) {
241                            return false;
242                    }
243                    final EaOptimizerConfigurationBase<?> other = (EaOptimizerConfigurationBase<?>) obj;
244                    if (evaluator == null) {
245                            if (other.evaluator != null) {
246                                    return false;
247                            }
248                    } else if (!evaluator.equals(other.evaluator)) {
249                            return false;
250                    }
251                    if (halter == null) {
252                            if (other.halter != null) {
253                                    return false;
254                            }
255                    } else if (!halter.equals(other.halter)) {
256                            return false;
257                    }
258                    if (mutator == null) {
259                            if (other.mutator != null) {
260                                    return false;
261                            }
262                    } else if (!mutator.equals(other.mutator)) {
263                            return false;
264                    }
265                    if (parents != other.parents) {
266                            return false;
267                    }
268                    if (preserveParents != other.preserveParents) {
269                            return false;
270                    }
271                    return true;
272            }
273    }