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 java.io.ByteArrayInputStream;
019 import java.io.ByteArrayOutputStream;
020 import java.io.IOException;
021 import java.io.ObjectInputStream;
022 import java.io.ObjectOutputStream;
023 import java.io.Serializable;
024
025 import org.apache.commons.math.random.RandomGenerator;
026 import org.apache.commons.math.random.Well44497b;
027
028 /**
029 * The base class of all {@link Optimizer} configurations.
030 * <p>
031 * Subclasses have to override {@link #clone()} to cast the result to themself
032 * and {@link #validate()} to validate them.
033 *
034 * @param <I>
035 * the individuals' type
036 *
037 * @author <a href="http://kumpe.de/christian/java">Christian Kumpe</a>
038 */
039 public abstract class OptimizerConfiguration<I> implements Serializable,
040 Cloneable {
041 private static final long serialVersionUID = 1L;
042
043 private final static class DefaultRandomGeneratorFactory implements
044 RandomGeneratorFactory {
045 private static final long serialVersionUID = 1L;
046
047 @Override
048 public RandomGenerator createRandomGenerator(final long seed) {
049 return new Well44497b(seed);
050 }
051
052 @Override
053 public int hashCode() {
054 return 0;
055 }
056
057 @Override
058 public boolean equals(final Object obj) {
059 if (null == obj) {
060 return false;
061 }
062 return getClass() == obj.getClass();
063 }
064 }
065
066 private PopulationReader<I> populationReader;
067 private PopulationWriter<I> populationWriter;
068 private RandomGeneratorFactory randomGeneratorFactory = new DefaultRandomGeneratorFactory();
069
070 /**
071 * Returns a shallow copy of this configuration. This will not clone the
072 * configuration's components.
073 * <p>
074 * Subclasses should override this method to cast the result to themself.
075 *
076 * @return the shallow copy of this configuration
077 */
078 @Override
079 @SuppressWarnings("unchecked")
080 public OptimizerConfiguration<I> clone() {
081 try {
082 return (OptimizerConfiguration<I>) super.clone();
083 } catch (final CloneNotSupportedException e) {
084 throw new AssertionError(); // Can't happen
085 }
086 }
087
088 /**
089 * @return the deep copy of the specified configuration
090 */
091 public static <I, T extends OptimizerConfiguration<I>> T deepClone(
092 final T original) {
093 try {
094 // serialize
095 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
096 final ObjectOutputStream oos = new ObjectOutputStream(bos);
097 oos.writeObject(original);
098 oos.close();
099
100 // deserialize
101 final ByteArrayInputStream bis = new ByteArrayInputStream(
102 bos.toByteArray());
103 final ObjectInputStream ois = new ObjectInputStream(bis);
104 @SuppressWarnings("unchecked")
105 final T clone = (T) ois.readObject();
106 ois.close();
107
108 return clone;
109 } catch (final IOException e) {
110 throw new RuntimeException(e);
111 } catch (final ClassNotFoundException e) {
112 throw new RuntimeException(e);
113 }
114 }
115
116 /**
117 * Validates the configuration for completeness and correctness.
118 * <p>
119 * Subclasses have to override this method, then first call this method from
120 * the superclass and then do their own additional validation.
121 * <p>
122 * Verifies that a {@link #setPopulationReader(PopulationReader)
123 * populationReader} and {@link #setPopulationWriter(PopulationWriter)
124 * populationWriter} has been set.
125 *
126 * @throws IllegalStateException
127 * if this configuration is not valid
128 */
129 public void validate() {
130 if (null == populationReader) {
131 throw new IllegalStateException(
132 "A PopulatioReader has to be set in the configuration.");
133 }
134 if (null == populationWriter) {
135 throw new IllegalStateException(
136 "A PopulationWriter has to be set in the configuration.");
137 }
138 }
139
140 /**
141 * Will inject the given {@link RandomGenerator} instance into all contained
142 * components which are implementing {@link NeedsRandomGenerator}.
143 * <p>
144 * Subclasses must override this method, if they contain additional
145 * components. Then first call this method from the superclass and then call
146 * {@link #injectRandomGenerator(Object, RandomGenerator)} for their
147 * additional components.
148 * <p>
149 * Calls {@link #injectRandomGenerator(Object, RandomGenerator)} on the
150 * given {@link #setPopulationReader(PopulationReader) populationReader} and
151 * {@link #setPopulationWriter(PopulationWriter) populationWriter}.
152 *
153 * @param randomGenerator
154 * the {@link RandomGenerator} instance to inject
155 */
156 public void injectRandomGenerator(final RandomGenerator randomGenerator) {
157 injectRandomGenerator(populationReader, randomGenerator);
158 injectRandomGenerator(populationWriter, randomGenerator);
159 }
160
161 /**
162 * Inject the given {@link RandomGenerator} object into the passed
163 * {@code instance}, if {@code instance} is implementing
164 * {@link NeedsRandomGenerator}.
165 *
166 * @param instance
167 * the instance for injecting the {@code randomGenerator}, if
168 * needed
169 * @param randomGenerator
170 * the {@link RandomGenerator} object to inject
171 */
172 protected final void injectRandomGenerator(final Object instance,
173 final RandomGenerator randomGenerator) {
174 if (instance instanceof NeedsRandomGenerator) {
175 ((NeedsRandomGenerator) instance)
176 .setRandomGenerator(randomGenerator);
177 }
178 }
179
180 /**
181 * @return the configured {@link PopulationReader}; <code>null</code> if
182 * none has been set
183 */
184 public final PopulationReader<I> getPopulationReader() {
185 return populationReader;
186 }
187
188 /**
189 * @param populationReader
190 * the {@link PopulationReader} for this configuration
191 *
192 * @throws NullPointerException
193 * if {@code populationReader} is <code>null</code>
194 */
195 public final void setPopulationReader(
196 final PopulationReader<I> populationReader) {
197 if (null == populationReader) {
198 throw new NullPointerException("populationReader may not be null.");
199 }
200
201 this.populationReader = populationReader;
202 }
203
204 /**
205 * @return the configured {@link PopulationWriter}; <code>null</code> if
206 * none has been set
207 */
208 public final PopulationWriter<I> getPopulationWriter() {
209 return populationWriter;
210 }
211
212 /**
213 * @param populationWriter
214 * the {@link PopulationWriter} for this configuration
215 *
216 * @throws NullPointerException
217 * if {@code populationWriter} is <code>null</code>
218 */
219 public final void setPopulationWriter(
220 final PopulationWriter<I> populationWriter) {
221 if (null == populationWriter) {
222 throw new NullPointerException("populationWriter may not be null.");
223 }
224
225 this.populationWriter = populationWriter;
226 }
227
228 /**
229 * @return the configured {@link RandomGeneratorFactory}; per default this
230 * returns a factory which creates instances of {@link Well44497b}
231 */
232 public RandomGeneratorFactory getRandomGeneratorFactory() {
233 assert null != randomGeneratorFactory;
234
235 return randomGeneratorFactory;
236 }
237
238 /**
239 * @param randomGeneratorFactory
240 * the {@link RandomGeneratorFactory} for this configuration
241 *
242 * @throws NullPointerException
243 * if {@code randomGeneratorFactory} is <code>null</code>
244 */
245 public void setRandomGeneratorFactory(
246 final RandomGeneratorFactory randomGeneratorFactory) {
247 if (null == randomGeneratorFactory) {
248 throw new NullPointerException(
249 "randomGeneratorFactory may not be null.");
250 }
251
252 this.randomGeneratorFactory = randomGeneratorFactory;
253 }
254
255 @Override
256 public int hashCode() {
257 assert null != randomGeneratorFactory;
258
259 final int prime = 31;
260 int result = 1;
261 result = prime * result
262 + (populationReader == null ? 0 : populationReader.hashCode());
263 result = prime * result
264 + (populationWriter == null ? 0 : populationWriter.hashCode());
265 result = prime * result + randomGeneratorFactory.hashCode();
266 return result;
267 }
268
269 @Override
270 public boolean equals(final Object obj) {
271 assert null != randomGeneratorFactory;
272
273 if (this == obj) {
274 return true;
275 }
276 if (obj == null) {
277 return false;
278 }
279 if (!(obj instanceof OptimizerConfiguration)) {
280 return false;
281 }
282 final OptimizerConfiguration<?> other = (OptimizerConfiguration<?>) obj;
283 if (populationReader == null) {
284 if (other.populationReader != null) {
285 return false;
286 }
287 } else if (!populationReader.equals(other.populationReader)) {
288 return false;
289 }
290 if (populationWriter == null) {
291 if (other.populationWriter != null) {
292 return false;
293 }
294 } else if (!populationWriter.equals(other.populationWriter)) {
295 return false;
296 }
297 return randomGeneratorFactory.equals(other.randomGeneratorFactory);
298 }
299 }