InversionMutation.java
/**
* @(#)InversionMutation.java
* Copyright (C) 2008-2011 delhezi.com
*
* This class is released under the:
* GNU Lesser General Public License (LGPL) version 3 or later.
* http://www.gnu.org/copyleft/lesser.html
*/
package com.delhezi.ga.mutation;
import com.delhezi.ga.Chromosome;
import java.util.Random;
//import java.util.logging.Logger;
/**
* Klasa <code>InversionMutation</code>: Mutacja przez inwersję
* Inversion Mutation (IVM).
* @version 1.0 2009-06-10
* @author <a href="mailto:wojciech.wolszczak@delhezi.com">
* Wojciech Wolszczak</a>
*/
public class InversionMutation implements IMutation {
/** Logger object. */
//private static final Logger LOGGER =
// Logger.getLogger(InversionMutation.class.getName());
/** Delhezi Error Code. */
//private static final String DERC = "1-6-1-";
/** Random.*/
private static Random random = new Random();
/**
* Implementacja funkcji mutacji przez inwersję.
* @param chromosome Chromosom podlegający mutacji.
* @since 1.0
*/
@Override
public final void mutation(final Chromosome chromosome) {
if (chromosome == null) {
throw new IllegalArgumentException("Chromosome is null.");
}
int chromosomeSize = chromosome.size();
//Chromosom ma tylko 1 gen.
if (chromosomeSize < 2) {
return;
}
//Losuje liczny z zakresu od 0 do chromosomeSize.
//Początkowy punkt fragmentu inwersji cutPoint1=2 dla xx|iiixxxxx.
int cutPoint1 = (int) (random.nextDouble() * (chromosomeSize + 1));
//Końcowy punkt fragmentu inwersji cutPoint2=5 dla xxiii|xxxxx.
int cutPoint2 = (int) (random.nextDouble() * (chromosomeSize + 1));
//Korekta wyniku.
//Istnieje bardzo małe prawdopodobienstwo wylosowania liczby o
//wartosci chromosomeSize (poza zakresem), np. 4.999999999999999
//zaokraglane jest do 4, ale sprawdzę:
if (cutPoint1 == chromosomeSize + 1) {
cutPoint1--;
}
if (cutPoint2 == chromosomeSize + 1) {
cutPoint2--;
}
//Liczba genów poza fragmentem inwersji.
int differentGenesSize = (cutPoint2 >= cutPoint1)
? chromosomeSize - (cutPoint2 - cutPoint1)
: chromosomeSize - (chromosomeSize - cutPoint1) - cutPoint2;
//Jeśli liczba genów fragmentu inwersji==0
if (chromosomeSize - differentGenesSize == 0) {
return;
}
//Losuje liczny z zakresu od 0 do chromosomeSize.
//Liczby miejsc do wstawienia genów fragmentu inwersji jest
//równa differentGenes + 1.
//insertPoint=2 dla xx|xxxxx
int insertPoint =
(int) (random.nextDouble() * (differentGenesSize + 1));
//Istnieje bardzo małe prawdopodobienstwo wylosowania liczby o
//wartosci differentGenesSize + 1 (poza zakresem),
//np. 4.999999999999999 zaokraglane jest do 4, ale sprawdzę:
if (insertPoint == differentGenesSize + 1) {
insertPoint--;
}
this.mutation(chromosome, cutPoint1, cutPoint2, insertPoint);
}
/**
* Implementacja funkcji mutacji przez inwersję;
* W przypadku kiedy
* (cutPoint1==cutPoint2 || (cutPoint1==chromosomeSize && cutPoint2==0))
* funkcja traktuje fragment dopasowania jako pusty.
* @param chromosome Chromosom podlegający mutacji.
* @param cutPoint1 Początkowy punkt fragmentu inwersji, wartość z
* zakresu <0, chromosomeSize>.
* Przykład: cutPoint1=2 dla xx|iiixxxxx.
* @param cutPoint2 Końcowy punkt fragmentu inwersji, wartość z
* zakresu <0, chromosomeSize>.
* Przykład: cutPoint2=5 dla xxiii|xxxxx.
* @param insertPoint Punkt do wstawienia odwróconych genów, wartość z
* zakresu <0, differentGenesSize>.
* Przykład: insertPoint=2 dla xx|xxxxx.
* Nie są brane pod uwagę geny fragmentu inwersji.
* @since 1.0
*/
protected final void mutation(final Chromosome chromosome,
final int cutPoint1,
final int cutPoint2,
final int insertPoint) {
//Walidacja parametrów wejściowych.
//Chromosom nie może być wartością null.
assert chromosome != null : "Illegal argument chromosome: null";
int chromosomeSize = chromosome.size();
//Punkt cutPoint1 powinien zawierać się w obszare chromosomu.
assert (cutPoint1 >= 0 && cutPoint1 <= chromosomeSize)
: "Illegal argument cutPoint1: " + cutPoint1;
//Punkt cutPoint2 powinien zawierać się w obszare chromosomu.
assert (cutPoint2 >= 0 && cutPoint2 <= chromosomeSize)
: "Illegal argument cutPoint2: " + cutPoint2;
//Funkcja traktuje fragment dopasowania jako pusty.
if (cutPoint1 == cutPoint2 || (cutPoint1 == chromosomeSize
&& cutPoint2 == 0)) {
return;
}
//Dla mniej niż 2 genów mutacja przez inwersję nie spowoduje
//żadnych zmian.
if (chromosomeSize < 2) {
return;
}
//Liczba genów podlegających inwersji.
int inversionGenesSize = (cutPoint1 < cutPoint2)
? cutPoint2 - cutPoint1
: (chromosomeSize - cutPoint1) + cutPoint2;
int differentGenesSize = chromosomeSize - inversionGenesSize;
//Punkt insertPoint powinien zawierać się w obszare chromosomu z
//pominięciem obszaru inwersji.
assert (insertPoint >= 0 && insertPoint <= differentGenesSize)
: "Illegal argument insertPoint: " + insertPoint;
//Koniec walidacji parametrów wejściowych.
//IMPLEMENTACJA DO ZMIANY, ZASTĄPIĆ WEKTORAMI.
//invGenes - sekcja inwersji po operacji inwersji.
Object[] invGenes = new Object[inversionGenesSize];
int ii = cutPoint2;
for (int i = 0; i < inversionGenesSize; i++) {
ii = (ii < 1) ? chromosomeSize - 1 : ii - 1;
invGenes[i] = chromosome.getGene(ii);
}
//cpGenes - pozostałe geny.
Object[] cpGenes = new Object[chromosomeSize - inversionGenesSize];
ii = 0;
int ii2 = cutPoint2;
if (cutPoint1 < cutPoint2) {
for (int i = 0; i < cpGenes.length; i++) {
ii = (ii < cutPoint1) ? ii : ii2++;
cpGenes[i] = chromosome.getGene(ii);
ii++;
}
}
ii = 0;
if (cutPoint2 < cutPoint1) {
for (int i = cutPoint2; i < cutPoint1; i++) {
cpGenes[ii] = chromosome.getGene(i);
ii++;
}
}
int inv = 0;
int cp = 0;
for (int i = 0; i < chromosomeSize; i++) {
if ((i < insertPoint) || (i >= insertPoint + inversionGenesSize)) {
chromosome.setGene(i, cpGenes[cp]);
cp++;
} else {
chromosome.setGene(i, invGenes[inv]);
inv++;
}
}
//Zasygnalizuj, ze chromosom został zmieniony.
chromosome.changed();
}
}