001/* 002 * Java Genetic Algorithm Library (jenetics-8.1.0). 003 * Copyright (c) 2007-2024 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 java.lang.String.format; 024 025import io.jenetics.util.MSeq; 026import io.jenetics.util.RandomRegistry; 027 028/** 029 * <strong>Single point crossover</strong> 030 * 031 * <p> 032 * One or two children are created by taking two parent strings and cutting 033 * them at some randomly chosen site. E.g. 034 * <p> 035 * <img src="doc-files/SinglePointCrossover.svg" width="400" 036 * alt="Single-point crossover" > 037 * <p> 038 * If we create a child and its complement we preserving the total number of 039 * genes in the population, preventing any genetic drift. 040 * Single-point crossover is the classic form of crossover. However, it produces 041 * very slow mixing compared with multi-point crossover or uniform crossover. 042 * For problems where the site position has some intrinsic meaning to the 043 * problem single-point crossover can lead to small disruption than multi-point 044 * or uniform crossover. 045 * 046 * @see MultiPointCrossover 047 * 048 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 049 * @since 1.0 050 * @version 5.0 051 */ 052public class SinglePointCrossover< 053 G extends Gene<?, G>, 054 C extends Comparable<? super C> 055> 056 extends MultiPointCrossover<G, C> 057{ 058 059 /** 060 * Constructs an alterer with a given recombination probability. 061 * 062 * @param probability the crossover probability. 063 * @throws IllegalArgumentException if the {@code probability} is not in the 064 * valid range of {@code [0, 1]}. 065 */ 066 public SinglePointCrossover(final double probability) { 067 super(probability, 1); 068 } 069 070 /** 071 * Create a new single-point crossover object with crossover probability of 072 * {@code 0.05}. 073 */ 074 public SinglePointCrossover() { 075 this(0.05); 076 } 077 078 @Override 079 protected int crossover(final MSeq<G> that, final MSeq<G> other) { 080 final var random = RandomRegistry.random(); 081 082 final int index = random.nextInt(min(that.length(), other.length())); 083 crossover(that, other, index); 084 return 2; 085 } 086 087 // Package private for testing purpose. 088 static <T> void crossover( 089 final MSeq<T> that, 090 final MSeq<T> other, 091 final int index 092 ) { 093 assert index >= 0 : 094 format( 095 "Crossover index must be within [0, %d) but was %d", 096 that.length(), index 097 ); 098 099 that.swap(index, min(that.length(), other.length()), other, index); 100 } 101 102 @Override 103 public String toString() { 104 return format("%s[p=%f]", getClass().getSimpleName(), _probability); 105 } 106 107}