Java tutorial
/** * Copyright 2012 George Belden * * This file is part of ZodiacGenetics. * * ZodiacGenetics is free software: you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * ZodiacGenetics is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * ZodiacGenetics. If not, see <http://www.gnu.org/licenses/>. */ package com.ciphertool.genetics.algorithms.mutation; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Required; import com.ciphertool.genetics.dao.GeneListDao; import com.ciphertool.genetics.entities.Chromosome; import com.ciphertool.genetics.entities.Gene; import com.ciphertool.genetics.util.ChromosomeHelper; public class LiberalMutationAlgorithm implements MutationAlgorithm { private static Logger log = Logger.getLogger(LiberalMutationAlgorithm.class); private GeneListDao geneListDao; private ChromosomeHelper chromosomeHelper; private Integer maxMutationsPerChromosome; private static final int MAX_FIND_ATTEMPTS = 1000; @Override public void mutateChromosome(Chromosome chromosome) { if (maxMutationsPerChromosome == null) { throw new IllegalStateException("The maxMutationsPerChromosome cannot be null."); } /* * Choose a random number of mutations constrained by the configurable * max and the total number of genes */ int numMutations = (int) (Math.random() * Math.min(maxMutationsPerChromosome, chromosome.getGenes().size())) + 1; List<Integer> geneIndices = new ArrayList<Integer>(); for (int i = 0; i < numMutations; i++) { // Keep track of the mutated indices geneIndices.add(mutateRandomGene(chromosome, geneIndices)); } } /** * Performs a genetic mutation of a random Gene of the supplied Chromosome * * @param chromosome * the Chromosome to mutate */ private Integer mutateRandomGene(Chromosome chromosome, List<Integer> geneIndices) { int randomIndex; // We don't want to reuse an index, so loop until we find a new one int attempts = 0; do { randomIndex = (int) (Math.random() * chromosome.getGenes().size()); attempts++; if (attempts >= MAX_FIND_ATTEMPTS) { if (log.isDebugEnabled()) { log.debug("Unable to find a previously unused Gene index after " + attempts + " attempts. Returning null."); } return null; } } while (geneIndices.contains(randomIndex)); mutateGene(chromosome, randomIndex); chromosomeHelper.resizeChromosome(chromosome); return randomIndex; } /** * Performs a genetic mutation of a specific Gene of the supplied Chromosome * * @param chromosome * the Chromosome to mutate * @param index * the index of the Gene to mutate */ private void mutateGene(Chromosome chromosome, int index) { if (index > chromosome.getGenes().size() - 1) { log.info("Attempted to mutate a Gene in Chromosome with index of " + index + " (zero-indexed), but the size is only " + chromosome.getGenes().size() + ". Cannot continue."); return; } /* * Loop just in case the value of the new Gene is the same as the * existing value, since that would defeat the purpose of the mutation. */ Gene oldGene = chromosome.getGenes().get(index); Gene newGene = null; int attempts = 0; do { newGene = geneListDao.findRandomGene(chromosome, oldGene.getSequences().get(0).getSequenceId()); attempts++; if (attempts >= MAX_FIND_ATTEMPTS) { if (log.isDebugEnabled()) { log.debug("Unable to find a different value for Gene " + oldGene + " after " + attempts + " attempts. Breaking out of the loop."); } break; } } while (chromosome.getGenes().get(index).equals(newGene)); chromosome.replaceGene(index, newGene); } /** * @param geneListDao * the geneListDao to set */ @Required public void setGeneListDao(GeneListDao geneListDao) { this.geneListDao = geneListDao; } /** * @param chromosomeHelper * the chromosomeHelper to set */ @Required public void setChromosomeHelper(ChromosomeHelper chromosomeHelper) { this.chromosomeHelper = chromosomeHelper; } @Override public void setMaxMutationsPerChromosome(Integer maxMutationsPerChromosome) { this.maxMutationsPerChromosome = maxMutationsPerChromosome; } }