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 io.jenetics.internal.math.Randoms.indexes; 023 024import java.util.random.RandomGenerator; 025 026import io.jenetics.internal.util.Counter; 027import io.jenetics.util.MSeq; 028 029/** 030 * The {@code SwapMutation} changes the order of genes in a chromosome, with the 031 * hope of bringing related genes closer together, thereby facilitating the 032 * production of building blocks. This mutation operator can also be used for 033 * combinatorial problems, where no duplicated genes within a chromosome are 034 * allowed, e.g., for the TSP. 035 * <p> 036 * This mutator is also known as <em>Partial Shuffle Mutator</em> (PSM). 037 * 038 * @see <a href="https://arxiv.org/ftp/arxiv/papers/1203/1203.3099.pdf"> 039 * Analyzing the Performance of Mutation Operators to Solve the Travelling 040 * Salesman Problem</a> 041 * 042 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a> 043 * @since 1.0 044 * @version 5.0 045 */ 046public class SwapMutator< 047 G extends Gene<?, G>, 048 C extends Comparable<? super C> 049> 050 extends Mutator<G, C> 051{ 052 053 /** 054 * Constructs an alterer with a given recombination probability. 055 * 056 * @param probability the crossover probability. 057 * @throws IllegalArgumentException if the {@code probability} is not in the 058 * valid range of {@code [0, 1]}. 059 */ 060 public SwapMutator(final double probability) { 061 super(probability); 062 } 063 064 /** 065 * Default constructor, with default mutation probability 066 * ({@link AbstractAlterer#DEFAULT_ALTER_PROBABILITY}). 067 */ 068 public SwapMutator() { 069 this(DEFAULT_ALTER_PROBABILITY); 070 } 071 072 /** 073 * Swaps the genes in the given array, with the mutation probability of this 074 * mutation. 075 */ 076 @Override 077 protected MutatorResult<Chromosome<G>> mutate( 078 final Chromosome<G> chromosome, 079 final double p, 080 final RandomGenerator random 081 ) { 082 final MutatorResult<Chromosome<G>> result; 083 if (chromosome.length() > 1) { 084 final MSeq<G> genes = MSeq.of(chromosome); 085 final int mutations = indexes(random, genes.length(), p) 086 .peek(i -> genes.swap(i, random.nextInt(genes.length()))) 087 .collect(Counter::new, Counter::inc, Counter::sum) 088 .intValue(); 089 090 result = new MutatorResult<>( 091 chromosome.newInstance(genes.toISeq()), 092 mutations 093 ); 094 } else { 095 result = new MutatorResult<>(chromosome, 0); 096 } 097 098 return result; 099 } 100 101}