001/* 002 * Java Genetic Algorithm Library (jenetics-9.0.0). 003 * Copyright (c) 2007-2026 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 */ 020package io.jenetics; 021 022import static java.lang.Math.min; 023import static io.jenetics.internal.math.Randoms.indexes; 024 025import io.jenetics.internal.util.Counter; 026import io.jenetics.internal.util.Requires; 027import io.jenetics.util.MSeq; 028import io.jenetics.util.RandomRegistry; 029 030/** 031 * The uniform crossover uses swaps single genes between two chromosomes, instead 032 * of whole ranges as in single- and multipoint crossover. 033 * <pre> {@code 034 * +---+---+---+---+---+---+---+ 035 * | 1 | 2 | 3 | 4 | 6 | 7 | 8 | 036 * +-+-+---+-+-+-+-+---+-+-+---+ 037 * | | | | swapping 038 * +-+-+---+-+-+-+-+---+-+-+---+ 039 * | a | b | c | d | e | f | g | 040 * +---+---+---+---+---+---+---+ 041 * } </pre> 042 * The probability that two genes are swapped is controlled by the 043 * <i>swap-probability</i> ({@link #swapProbability()}), whereas the 044 * probability that a given individual is selected for crossover is defined by 045 * the <i>crossover-probability</i> ({@link #probability()}). 046 * 047 * @see <a href="https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)#Uniform_crossover_and_half_uniform_crossover"> 048 * Wikipedia: Uniform crossover</a> 049 * 050 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 051 * @version 6.0 052 * @since 3.7 053 */ 054public class UniformCrossover< 055 G extends Gene<?, G>, 056 C extends Comparable<? super C> 057> 058 extends Crossover<G, C> 059{ 060 061 private final double _swapProbability; 062 063 /** 064 * Create a new universal crossover instance. 065 * 066 * @param crossoverProbability the recombination probability as defined in 067 * {@link Crossover#Crossover(double)}. This is the probability that 068 * a given individual is selected for crossover. 069 * @param swapProbability the probability for swapping a given gene of 070 * a chromosome 071 * @throws IllegalArgumentException if the probabilities are not in the 072 * valid range of {@code [0, 1]} 073 */ 074 public UniformCrossover( 075 final double crossoverProbability, 076 final double swapProbability 077 ) { 078 super(crossoverProbability); 079 _swapProbability = Requires.probability(swapProbability); 080 } 081 082 /** 083 * Create a new universal crossover instance. The {@code swapProbability} is 084 * set to {@link Alterer#DEFAULT_ALTER_PROBABILITY}. 085 * 086 * @param crossoverProbability the recombination probability as defined in 087 * {@link Crossover#Crossover(double)}. This is the probability that 088 * a given individual is selected for crossover. 089 * @throws IllegalArgumentException if the probabilities are not in the 090 * valid range of {@code [0, 1]} 091 */ 092 public UniformCrossover(final double crossoverProbability) { 093 this(crossoverProbability, DEFAULT_ALTER_PROBABILITY); 094 } 095 096 /** 097 * Create a new universal crossover instance. The probabilities are set to 098 * {@link Alterer#DEFAULT_ALTER_PROBABILITY}. 099 */ 100 public UniformCrossover() { 101 this(DEFAULT_ALTER_PROBABILITY, DEFAULT_ALTER_PROBABILITY); 102 } 103 104 /** 105 * Return the probability for swapping genes of a chromosome. 106 * 107 * @return the probability for swapping genes of a chromosome 108 */ 109 public double swapProbability() { 110 return _swapProbability; 111 } 112 113 @Override 114 protected int crossover(final MSeq<G> that, final MSeq<G> other) { 115 final int length = min(that.length(), other.length()); 116 return indexes(RandomRegistry.random(), length, _swapProbability) 117 .peek(i -> that.swap(i, other)) 118 .collect(Counter::new, Counter::inc, Counter::sum) 119 .intValue(); 120 } 121 122}