001    package org.jaga.reproduction.greycodedNumbers;
002    
003    import org.jaga.definitions.*;
004    import org.jaga.util.*;
005    import org.jaga.individualRepresentation.greycodedNumbers.*;
006    import org.jaga.reproduction.*;
007    
008    
009    /**
010     * TODO: Complete these comments.
011     *
012     * <p><u>Project:</u> JAGA - Java API for Genetic Algorithms.</p>
013     *
014     * <p><u>Company:</u> University College London and JAGA.Org
015     *    (<a href="http://www.jaga.org" target="_blank">http://www.jaga.org</a>).
016     * </p>
017     *
018     * <p><u>Copyright:</u> (c) 2004 by G. Paperin.<br/>
019     *    This program is free software; you can redistribute it and/or modify
020     *    it under the terms of the GNU General Public License as published by
021     *    the Free Software Foundation, ONLY if you include a note of the original
022     *    author(s) in any redistributed/modified copy.<br/>
023     *    This program is distributed in the hope that it will be useful,
024     *    but WITHOUT ANY WARRANTY; without even the implied warranty of
025     *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
026     *    GNU General Public License for more details.<br/>
027     *    You should have received a copy of the GNU General Public License
028     *    along with this program; if not, write to the Free Software
029     *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
030     *    or see http://www.gnu.org/licenses/gpl.html</p>
031     *
032     * @author Greg Paperin (greg@jaga.org)
033     *
034     * @version JAGA public release 1.0 beta
035     */
036    
037    public class SimpleBinaryXOver extends XOver {
038    
039            private static final Class applicableClass = BinaryEncodedIndividual.class;
040    
041            public SimpleBinaryXOver() {
042                    super();
043            }
044    
045            public SimpleBinaryXOver(double xOverProb) {
046                    super(xOverProb);
047            }
048    
049            public Class getApplicableClass() {
050                    return applicableClass;
051            }
052    
053            public Individual[] reproduce(Individual[] parents, GAParameterSet params) {
054                    if (parents.length != getRequiredNumberOfParents())
055                            throw new IllegalArgumentException("Need " + getRequiredNumberOfParents()
056                                                                                               + " parents for reproduction (not "
057                                                                                               + parents.length + ")");
058    
059                    // Check correct type for parents, get length:
060                    int bitLen = checkParentsTypeAndLength(parents);
061    
062                    // Chance (1 - xover probability) that parents wont be changed:
063                    final RandomGenerator rnd = params.getRandomGenerator();
064    
065                    if (rnd.nextDouble() >= getXOverProbability())
066                            return makeCopyOfParents(parents, params);
067    
068                    // Get parents bitsrings:
069                    BitString p1 = ((BinaryEncodedIndividual) parents[0]).getBitStringRepresentation();
070                    BitString p2 = ((BinaryEncodedIndividual) parents[1]).getBitStringRepresentation();
071    
072                    // x-over:
073                    final int maxAttempts = params.getMaxBadReproductionAttempts();
074    
075                    int attempts = 0;
076                    boolean kidsAreValid = false;
077                    do {
078                            kidsAreValid = false;
079                            int xPoint = rnd.nextInt(1, bitLen);
080    
081                            // offspring bit strings:
082                            BitString c1 = new BitString(bitLen);
083                            BitString c2 = new BitString(bitLen);
084    
085                            // copy before xover-point:
086                            for (int i = 0; i < xPoint; i++) {
087                                    c1.set(i, p1.get(i));
088                                    c2.set(i, p2.get(i));
089                            }
090    
091                            // copy after xover-point:
092                            for (int i = xPoint; i < bitLen; i++) {
093                                    c1.set(i, p2.get(i));
094                                    c2.set(i, p1.get(i));
095                            }
096    
097                            // create children and check if children are valid:
098                            NDecimalsIndividual [] kids = createKidsFromEncoding(params, c1, c2);
099                            kidsAreValid = kidsSatisfyConstraints(kids, params);
100    
101                            // return valid kids or have another attempts:
102                            if (kidsAreValid)
103                                    return kids;
104                            else
105                                    attempts++;
106    
107                    } while(!kidsAreValid && attempts < maxAttempts);
108    
109                    // all attempts failed:
110                    return makeCopyOfParents(parents, params);
111    
112            }
113    
114            protected Individual [] makeCopyOfParents(Individual [] parents, GAParameterSet params) {
115                    Individual [] kids = new Individual[parents.length];
116                    for (int i = 0; i < kids.length; i++) {
117                            kids[i] = params.getIndividualsFactory().createSpecificIndividual(
118                                                       ((BinaryEncodedIndividual)parents[i]).getBitStringRepresentation(),
119                                                       params);
120                            //kids[i] = (BinaryEncodedIndividual) ((BinaryEncodedIndividual) parents[i]).clone();
121                            kids[i].setFitness(parents[i].getFitness());
122                    }
123                    return kids;
124            }
125    
126            private int checkParentsTypeAndLength(Individual[] parents) throws IllegalArgumentException {
127                    // Now make sure that parents are of right type and equal length:
128                              int bitLen = -1;
129                              for (int i = 0; i < parents.length; i++) {
130                                      // Check type:
131                                      if (!getApplicableClass().isInstance(parents[i]))
132                                              throw new IllegalArgumentException("SimpleBinaryXOver works only for "
133                                                                                                               + getApplicableClass().getName()
134                                                                                                               + ", but parent is "
135                                                                                                               + parents[i].getClass().getName());
136                                      if (0 == i) // Remember bit len of first parent:
137                                              bitLen = ((BinaryEncodedIndividual) parents[i]).getBitStringRepresentation().getLength();
138                                      else        // And compare it to the bit len of all other parents:
139                                              if (bitLen != ((BinaryEncodedIndividual) parents[i]).getBitStringRepresentation().getLength())
140                                                      throw new IllegalArgumentException("SimpleBinaryXOver works only on "
141                                                                                                      + getApplicableClass() + " of equal representation length ("
142                                                                                                      + bitLen  + "!="
143                                                                                                      + ((BinaryEncodedIndividual) parents[i]).getBitStringRepresentation().getLength());
144                              }
145                    return bitLen;
146            }
147    
148            private boolean kidsSatisfyConstraints(NDecimalsIndividual[] kids, GAParameterSet params) {
149                    NDecimalsIndividualSimpleFactory fact = (NDecimalsIndividualSimpleFactory) params.getIndividualsFactory();
150                    for (int i = 0; i < kids.length; i++)
151                            if (!fact.valid(kids[i]))
152                                    return false;
153                    return true;
154            }
155    
156            private NDecimalsIndividual [] createKidsFromEncoding(GAParameterSet params, BitString c1, BitString c2) {
157                    NDecimalsIndividual [] kids = new NDecimalsIndividual[getRequiredNumberOfParents()];
158                    kids[0] = (NDecimalsIndividual)
159                                             params.getIndividualsFactory().createSpecificIndividual(c1, params);
160                    kids[1] = (NDecimalsIndividual)
161                                             params.getIndividualsFactory().createSpecificIndividual(c2, params);
162                    return kids;
163            }
164    
165    }