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 org.apache.commons.logging.Log;
021    import org.apache.commons.logging.LogFactory;
022    import org.apache.commons.math.random.RandomGenerator;
023    
024    import de.kumpe.hadooptimizer.EsIndividual;
025    import de.kumpe.hadooptimizer.EsWrappableMutator;
026    import de.kumpe.hadooptimizer.Mutator;
027    
028    /**
029     * Wrapp's a given {@link EsWrappableMutator} to mutate the {@code double[]}
030     * -individual nested in an {@link EsIndividual}.
031     * <p>
032     * It randomly increases or reduces the {@link EsIndividual}'s increment by a
033     * given factor.
034     * 
035     * @author <a href="http://kumpe.de/christian/java">Christian Kumpe</a>
036     */
037    
038    public final class EsMutatorWrapper extends
039                    NeedsRandomWrapperBase<EsWrappableMutator> implements
040                    Mutator<EsIndividual> {
041            private static final long serialVersionUID = 1L;
042            private static final Log log = LogFactory.getLog(EsMutatorWrapper.class);
043    
044            private final double incrementFactor;
045            private RandomGenerator randomGenerator;
046    
047            /**
048             * Creates a new {@link EsMutatorWrapper} wrapping the specified
049             * {@link EsWrappableMutator}.
050             * 
051             * @param delegate
052             *            an {@link EsWrappableMutator} to wrap
053             */
054            public EsMutatorWrapper(final EsWrappableMutator delegate) {
055                    this(delegate, 1.3d);
056            }
057    
058            /**
059             * Creates a new {@link EsMutatorWrapper} wrapping the specified
060             * {@link EsWrappableMutator}.
061             * 
062             * @param delegate
063             *            an {@link EsWrappableMutator} to wrap
064             * @param incrementFactor
065             *            the factor by which the current increment is randomly
066             *            increased or reduced
067             */
068            public EsMutatorWrapper(final EsWrappableMutator delegate,
069                            final double incrementFactor) {
070                    super(delegate);
071    
072                    if (log.isDebugEnabled()) {
073                            log.debug(format(
074                                            "Constructing new EsMutatorWrapper with a increment factor of %s which wraps %s",
075                                            incrementFactor, delegate));
076                    }
077    
078                    this.incrementFactor = incrementFactor;
079            }
080    
081            @Override
082            public void setRandomGenerator(final RandomGenerator randomGenerator) {
083                    super.setRandomGenerator(randomGenerator);
084    
085                    this.randomGenerator = randomGenerator;
086            }
087    
088            @Override
089            public EsIndividual mutate(final EsIndividual individual) {
090                    final double oldIncrement = individual.getIncrement();
091                    double newIncrement;
092                    if (randomGenerator.nextBoolean()) {
093                            newIncrement = oldIncrement * incrementFactor;
094                    } else {
095                            newIncrement = oldIncrement / incrementFactor;
096                    }
097                    final double sqrt = Math.sqrt(individual.getIndividual().length);
098                    if (newIncrement < delegate.getMinIncrement()) {
099                            newIncrement = delegate.getMinIncrement();
100                    }
101                    final double standardDeviation = newIncrement / sqrt;
102                    final double[] newIndividual = delegate.mutate(
103                                    individual.getIndividual(), standardDeviation);
104                    return new EsIndividual(newIndividual, newIncrement);
105            }
106    
107            @Override
108            public int hashCode() {
109                    final int prime = 31;
110                    int result = super.hashCode();
111                    long temp;
112                    temp = Double.doubleToLongBits(incrementFactor);
113                    result = prime * result + (int) (temp ^ temp >>> 32);
114                    return result;
115            }
116    
117            @Override
118            public boolean equals(final Object obj) {
119                    if (this == obj) {
120                            return true;
121                    }
122                    if (!super.equals(obj)) {
123                            return false;
124                    }
125                    if (!(obj instanceof EsMutatorWrapper)) {
126                            return false;
127                    }
128                    final EsMutatorWrapper other = (EsMutatorWrapper) obj;
129                    return Double.doubleToLongBits(incrementFactor) == Double
130                                    .doubleToLongBits(other.incrementFactor);
131            }
132    
133            @Override
134            public String toString() {
135                    return "EsEvaluatorWrapper [incrementFactor=" + incrementFactor
136                                    + ", delegate=" + delegate + "]";
137            }
138    }