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 &quot;duplicate&quot; 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    }