001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021
022
023package org.biojavax.ga.functions;
024
025import java.util.ArrayList;
026import java.util.Random;
027
028import org.biojava.bio.BioError;
029import org.biojava.bio.symbol.Edit;
030import org.biojava.bio.symbol.IllegalAlphabetException;
031import org.biojava.bio.symbol.PointLocation;
032import org.biojava.bio.symbol.SymbolList;
033import org.biojava.utils.ChangeVetoException;
034
035/**
036 * <p>Simple Implementation of the <code>CrossOverFunction</code> interface</p>
037 *
038 * @author Mark Schreiber
039 * @version 1.0
040 * @since 1.5
041 */
042
043public class SimpleCrossOverFunction extends AbstractCrossOverFunction {
044
045  public SimpleCrossOverFunction() {
046  }
047
048
049  // This is the one that actually does the work
050  public GACrossResult performCrossOver(SymbolList chromA,
051                                        SymbolList chromB)
052    throws ChangeVetoException {
053
054    ArrayList crossPoints = new ArrayList();
055    Random rand = new Random();
056
057    //do the actual crossing!
058    double crossProb;
059    //don't use <= crhomA.length() as there is no point crossing at the last pos
060    for (int i = 1; i < chromA.length() && i < chromB.length(); i++) {
061
062      //crossOverProbs might be shorter than i, in this case use the last prob
063      if(i - 1 > getCrossOverProbs().length -1)
064        crossProb = getCrossOverProbs()[getCrossOverProbs().length -1];
065      else
066        crossProb = getCrossOverProbs()[i-1];
067
068      if(crossPoints.size() >= getMaxCrossOvers())
069        break;
070
071      if(rand.nextDouble() <= crossProb){
072
073
074        //record the cross
075        crossPoints.add(new PointLocation(i));
076
077        //do a cross over
078        SymbolList aReplace = chromB.subList(i, chromB.length());
079        SymbolList bReplace = chromA.subList(i, chromA.length());
080
081        //replace chromA from cross point down with chromB from crosspoint down
082        Edit ed = new Edit(i, aReplace.length(), aReplace);
083        try {
084          chromA.edit(ed);
085        }catch (IllegalAlphabetException ex) {
086          //can't happen
087          throw new BioError(ex);
088        }
089
090        //do the reciprocal
091        ed = new Edit(i, bReplace.length(), bReplace);
092        try {
093          chromB.edit(ed);
094        }
095        catch (IllegalAlphabetException ex) {
096          throw new BioError(ex);
097        }
098      }
099    }
100
101
102    PointLocation[] crosses = new PointLocation[crossPoints.size()];
103    crosses = (PointLocation[])crossPoints.toArray(crosses);
104    return new SimpleGACrossResult(crosses, new SymbolList[]{chromA, chromB});
105  }
106}