OnePointCrossover.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.math4.legacy.genetics;

  18. import java.util.ArrayList;
  19. import java.util.List;

  20. import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
  21. import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
  22. import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;


  23. /**
  24.  * One point crossover policy. A random crossover point is selected and the
  25.  * first part from each parent is copied to the corresponding child, and the
  26.  * second parts are copied crosswise.
  27.  *
  28.  * Example:
  29.  * <pre>
  30.  * -C- denotes a crossover point
  31.  *                   -C-                                 -C-
  32.  * p1 = (1 0 1 0 0 1  | 0 1 1)    X    p2 = (0 1 1 0 1 0  | 1 1 1)
  33.  *      \------------/ \-----/              \------------/ \-----/
  34.  *            ||         (*)                       ||        (**)
  35.  *            VV         (**)                      VV        (*)
  36.  *      /------------\ /-----\              /------------\ /-----\
  37.  * c1 = (1 0 1 0 0 1  | 1 1 1)    X    c2 = (0 1 1 0 1 0  | 0 1 1)
  38.  * </pre>
  39.  *
  40.  * This policy works only on {@link AbstractListChromosome}, and therefore it
  41.  * is parameterized by T. Moreover, the chromosomes must have same lengths.
  42.  *
  43.  * @param <T> generic type of the {@link AbstractListChromosome}s for crossover
  44.  * @since 2.0
  45.  *
  46.  */
  47. public class OnePointCrossover<T> implements CrossoverPolicy {

  48.     /**
  49.      * Performs one point crossover. A random crossover point is selected and the
  50.      * first part from each parent is copied to the corresponding child, and the
  51.      * second parts are copied crosswise.
  52.      *
  53.      * Example:
  54.      * <pre>
  55.      * -C- denotes a crossover point
  56.      *                   -C-                                 -C-
  57.      * p1 = (1 0 1 0 0 1  | 0 1 1)    X    p2 = (0 1 1 0 1 0  | 1 1 1)
  58.      *      \------------/ \-----/              \------------/ \-----/
  59.      *            ||         (*)                       ||        (**)
  60.      *            VV         (**)                      VV        (*)
  61.      *      /------------\ /-----\              /------------\ /-----\
  62.      * c1 = (1 0 1 0 0 1  | 1 1 1)    X    c2 = (0 1 1 0 1 0  | 0 1 1)
  63.      * </pre>
  64.      *
  65.      * @param first first parent (p1)
  66.      * @param second second parent (p2)
  67.      * @return pair of two children (c1,c2)
  68.      * @throws MathIllegalArgumentException iff one of the chromosomes is
  69.      *   not an instance of {@link AbstractListChromosome}
  70.      * @throws DimensionMismatchException if the length of the two chromosomes is different
  71.      */
  72.     @Override
  73.     @SuppressWarnings("unchecked") // OK because of instanceof checks
  74.     public ChromosomePair crossover(final Chromosome first, final Chromosome second)
  75.         throws DimensionMismatchException, MathIllegalArgumentException {

  76.         if (! (first instanceof AbstractListChromosome<?> && second instanceof AbstractListChromosome<?>)) {
  77.             throw new MathIllegalArgumentException(LocalizedFormats.INVALID_FIXED_LENGTH_CHROMOSOME);
  78.         }
  79.         return crossover((AbstractListChromosome<T>) first, (AbstractListChromosome<T>) second);
  80.     }


  81.     /**
  82.      * Helper for {@link #crossover(Chromosome, Chromosome)}. Performs the actual crossover.
  83.      *
  84.      * @param first the first chromosome.
  85.      * @param second the second chromosome.
  86.      * @return the pair of new chromosomes that resulted from the crossover.
  87.      * @throws DimensionMismatchException if the length of the two chromosomes is different
  88.      */
  89.     private ChromosomePair crossover(final AbstractListChromosome<T> first,
  90.                                      final AbstractListChromosome<T> second) throws DimensionMismatchException {
  91.         final int length = first.getLength();
  92.         if (length != second.getLength()) {
  93.             throw new DimensionMismatchException(second.getLength(), length);
  94.         }

  95.         // array representations of the parents
  96.         final List<T> parent1Rep = first.getRepresentation();
  97.         final List<T> parent2Rep = second.getRepresentation();
  98.         // and of the children
  99.         final List<T> child1Rep = new ArrayList<>(length);
  100.         final List<T> child2Rep = new ArrayList<>(length);

  101.         // select a crossover point at random (0 and length makes no sense)
  102.         final int crossoverIndex = 1 + (GeneticAlgorithm.getRandomGenerator().nextInt(length-2));

  103.         // copy the first part
  104.         for (int i = 0; i < crossoverIndex; i++) {
  105.             child1Rep.add(parent1Rep.get(i));
  106.             child2Rep.add(parent2Rep.get(i));
  107.         }
  108.         // and switch the second part
  109.         for (int i = crossoverIndex; i < length; i++) {
  110.             child1Rep.add(parent2Rep.get(i));
  111.             child2Rep.add(parent1Rep.get(i));
  112.         }

  113.         return new ChromosomePair(first.newFixedLengthChromosome(child1Rep),
  114.                                   second.newFixedLengthChromosome(child2Rep));
  115.     }
  116. }