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.impl;
017
018 import static java.lang.String.*;
019
020 import java.util.ArrayList;
021 import java.util.Collection;
022
023 import org.apache.commons.logging.Log;
024 import org.apache.commons.logging.LogFactory;
025 import org.apache.commons.math.random.RandomGenerator;
026
027 import de.kumpe.hadooptimizer.EvaluationResult;
028 import de.kumpe.hadooptimizer.NeedsRandomGenerator;
029 import de.kumpe.hadooptimizer.Recombiner;
030
031 /**
032 * A {@link Recombiner} which creates the given number of offspring by randomly
033 * selecting and duplicating a parents.
034 * <p>
035 * It does not copy the parents! It only "duplicate" the reference.
036 *
037 * @param <I>
038 * the individual's type
039 *
040 * @author <a href="http://kumpe.de/christian/java">Christian Kumpe</a>
041 */
042 public final class DuplicatingRecombiner<I> implements Recombiner<I>,
043 NeedsRandomGenerator {
044 private static final long serialVersionUID = 1L;
045 private static final Log log = LogFactory
046 .getLog(DuplicatingRecombiner.class);
047
048 private final int offspring;
049 private RandomGenerator randomGenerator;
050
051 /**
052 * Creates a new {@link DuplicatingRecombiner} which generated the given
053 * number of offspring.
054 *
055 * @param offspring
056 * the number of offspring to create in
057 * {@link #recombine(Collection) recombination}
058 */
059 public DuplicatingRecombiner(final int offspring) {
060 if (0 >= offspring) {
061 throw new IllegalArgumentException(
062 "offspring must be greater than zero");
063 }
064
065 if (log.isDebugEnabled()) {
066 log.debug(format(
067 "Constructing new DuplicatingPairingSelector which creates %d offspring.",
068 offspring));
069 }
070
071 this.offspring = offspring;
072 }
073
074 @Override
075 public void setRandomGenerator(final RandomGenerator randomGenerator) {
076 this.randomGenerator = randomGenerator;
077 }
078
079 public int getOffspring() {
080 return offspring;
081 }
082
083 @Override
084 public Collection<I> recombine(
085 final Collection<EvaluationResult<I>> parentResults) {
086 if (log.isTraceEnabled()) {
087 log.trace(format("Duplicating %d parents to %d offspring.",
088 parentResults.size(), offspring));
089 }
090
091 final int nrOfParents = parentResults.size();
092 @SuppressWarnings("unchecked")
093 final EvaluationResult<I>[] parentsAsArray = (EvaluationResult<I>[]) parentResults
094 .toArray(new EvaluationResult<?>[nrOfParents]);
095 final Collection<I> children = new ArrayList<I>(offspring);
096
097 // create offspring children
098 for (int i = 0; i < offspring; i++) {
099 final int selectedParent = randomGenerator.nextInt(nrOfParents);
100 children.add(parentsAsArray[selectedParent].getIndividual());
101 }
102
103 return children;
104 }
105 }