Recombinator.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-4.0.0).
003  * Copyright (c) 2007-2017 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics;
021 
022 import static java.lang.String.format;
023 import static io.jenetics.internal.math.comb.subset;
024 import static io.jenetics.internal.math.random.indexes;
025 
026 import java.util.Random;
027 import java.util.function.IntFunction;
028 
029 import io.jenetics.util.MSeq;
030 import io.jenetics.util.RandomRegistry;
031 import io.jenetics.util.Seq;
032 
033 /**
034  <p>
035  * An enhanced genetic algorithm (EGA) combine elements of existing solutions in
036  * order to create a new solution, with some of the properties of each parent.
037  * Recombination creates a new chromosome by combining parts of two (or more)
038  * parent chromosomes. This combination of chromosomes can be made by selecting
039  * one or more crossover points, splitting these chromosomes on the selected
040  * points, and merge those portions of different chromosomes to form new ones.
041  </p>
042  <p>
043  * The recombination probability <i>P(r)</i> determines the probability that a
044  * given individual (genotype, not gene) of a population is selected for
045  * recombination. The (<i>mean</i>) number of changed individuals depend on the
046  * concrete implementation and can be vary from
047  <i>P(r)</i>&middot;<i>N<sub>G</sub></i> to
048  <i>P(r)</i>&middot;<i>N<sub>G</sub></i>&middot;<i>O<sub>R</sub></i>, where
049  <i>O<sub>R</sub></i> is the order of the recombination, which is the number
050  * of individuals involved int the {@link #recombine} method.
051  </p>
052  *
053  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
054  @since 1.0
055  @version 4.0
056  */
057 public abstract class Recombinator<
058     extends Gene<?, G>,
059     extends Comparable<? super C>
060 >
061     extends AbstractAlterer<G, C>
062 {
063 
064     private final int _order;
065 
066     /**
067      * Constructs an alterer with a given recombination probability.
068      *
069      @param probability The recombination probability.
070      @param order the number of individuals involved in the
071      *        {@link #recombine(MSeq, int[], long)} step
072      @throws IllegalArgumentException if the {@code probability} is not in the
073      *         valid range of {@code [0, 1]} or the given {@code order} is
074      *         smaller than two.
075      */
076     protected Recombinator(final double probability, final int order) {
077         super(probability);
078         if (order < 2) {
079             throw new IllegalArgumentException(format(
080                 "Order must be greater than one, but was %d.", order
081             ));
082         }
083         _order = order;
084     }
085 
086     /**
087      * Return the number of individuals involved in the
088      {@link #recombine(MSeq, int[], long)} step.
089      *
090      @return the number of individuals involved in the recombination step.
091      */
092     public int getOrder() {
093         return _order;
094     }
095 
096     @Override
097     public final AltererResult<G, C> alter(
098         final Seq<Phenotype<G, C>> population,
099         final long generation
100     ) {
101         final AltererResult<G, C> result;
102         if (population.size() >= 2) {
103             final Random random = RandomRegistry.getRandom();
104             final int order = Math.min(_order, population.size());
105 
106             // Selection of the individuals for recombination.
107             final IntFunction<int[]> individuals = i -> {
108                 final int[] ind = subset(population.size(), order, random);
109                 ind[0= i;
110                 return ind;
111             };
112 
113             final MSeq<Phenotype<G, C>> pop = MSeq.of(population);
114             final int count = indexes(random, population.size(), _probability)
115                 .mapToObj(individuals)
116                 .mapToInt(i -> recombine(pop, i, generation))
117                 .sum();
118 
119             result = AltererResult.of(pop.toISeq(), count);
120         else {
121             result = AltererResult.of(population.asISeq());
122         }
123 
124         return result;
125     }
126 
127     /**
128      * Recombination template method. This method is called 0 to n times. It is
129      * guaranteed that this method is only called by one thread.
130      *
131      @param population the population to recombine
132      @param individuals the array with the indexes of the individuals which
133      *        are involved in the <i>recombination</i> step. The length of the
134      *        array is {@link #getOrder()}. The first individual is the
135      *        <i>primary</i> individual.
136      @param generation the current generation.
137      @return the number of genes that has been altered.
138      */
139     protected abstract int recombine(
140         final MSeq<Phenotype<G, C>> population,
141         final int[] individuals,
142         final long generation
143     );
144 
145 }