//============================================================================= // Copyright 2006-2010 Daniel W. Dyer // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //============================================================================= package org.uncommons.watchmaker.framework.operators; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; import org.uncommons.maths.number.ConstantGenerator; import org.uncommons.maths.number.NumberGenerator; import org.uncommons.watchmaker.framework.EvolutionaryOperator; /** * A special mutation implementation that instead of changing the * genes of the candidate, re-orders them. A single mutation involves * swapping a random element in the list with the element immediately * after it. This operation can either apply a fixed number of * mutations to each candidate or it can draw values from a random * sequence, typically a poisson distribution (see * {@link org.uncommons.maths.random.PoissonGenerator}), to determine how * many mutations to apply. * @param <T> The component type of the lists that are mutated. * @author Daniel Dyer */ public class ListOrderMutation<T> implements EvolutionaryOperator<List<T>> { private final NumberGenerator<Integer> mutationCountVariable; private final NumberGenerator<Integer> mutationAmountVariable; /** * Default is one mutation per candidate. */ public ListOrderMutation() { this(1, 1); } /** * @param mutationCount The constant number of mutations * to apply to each individual in the population. * @param mutationAmount The constant number of positions by * which a list element will be displaced as a result of mutation. */ public ListOrderMutation(int mutationCount, int mutationAmount) { this(new ConstantGenerator<Integer>(mutationCount), new ConstantGenerator<Integer>(mutationAmount)); } /** * Typically the mutation count will be from a Poisson distribution. * The mutation amount can be from any discrete probability distribution * and can include negative values. * @param mutationCount A random variable that provides a number * of mutations that will be applied to each individual. * @param mutationAmount A random variable that provides a number * of positions by which to displace an element when mutating. */ public ListOrderMutation(NumberGenerator<Integer> mutationCount, NumberGenerator<Integer> mutationAmount) { this.mutationCountVariable = mutationCount; this.mutationAmountVariable = mutationAmount; } public List<List<T>> apply(List<List<T>> selectedCandidates, Random rng) { List<List<T>> result = new ArrayList<List<T>>(selectedCandidates.size()); for (List<T> candidate : selectedCandidates) { List<T> newCandidate = new ArrayList<T>(candidate); int mutationCount = Math.abs(mutationCountVariable.nextValue()); for (int i = 0; i < mutationCount; i++) { int fromIndex = rng.nextInt(newCandidate.size()); int mutationAmount = mutationAmountVariable.nextValue(); int toIndex = (fromIndex + mutationAmount) % newCandidate.size(); if (toIndex < 0) { toIndex += newCandidate.size(); } // Swap the randomly selected element with the one that is the // specified displacement distance away. Collections.swap(newCandidate, fromIndex, toIndex); } result.add(newCandidate); } return result; } }