KPointCrossover.java

/**
 * @(#)KPointCrossover.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.crossover.standard;

import com.delhezi.ga.Chromosome;
import com.delhezi.ga.utility.RandomUniqueInteger;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;

/**
 * <code>KPointCrossover</code>: Krzyżowanie wielopunktowe
 * k-Point Crossover (k-PX).
 * @version 1.0 2009-06-10
 * @author <a href="mailto:wojciech.wolszczak@delhezi.com">
 * Wojciech Wolszczak</a>
 */
public class KPointCrossover implements com.delhezi.ga.crossover.ICrossover {

    /** Logger object. */
    private static final Logger LOGGER =
        Logger.getLogger(KPointCrossover.class.getName());

    /** Delhezi Error Code. */
    //private static final String DERC = "1-1.3-3-";

    /** Class name. */
    private static final String CLASS_NAME = KPointCrossover.class.getName();

    /** Ilość punktów krzyżowania.*/
    private int k = 1;

    /**
     * Krzyżowanie.
     * @param chromosome1 Chromosom.
     * @param chromosome2 Chromosom.
     * @since 1.0
     */
    public final void crossover(final Chromosome chromosome1,
                                final Chromosome chromosome2) {
        LOGGER.entering(CLASS_NAME, "crossover",
                        new Object[] { chromosome1, chromosome2 });
        this.crossover(chromosome1, chromosome2, this.k);
        LOGGER.exiting(CLASS_NAME, "crossover",
                       new Object[] { chromosome1, chromosome2 });
    }

    /**
     * Krzyżowanie.
     * @param chromosome1 Chromosom.
     * @param chromosome2 Chromosom.
     * @param k Ilość punktów krzyżowania,
     * wartość z przedziału <1,chromosome1.size()-1>.
     * @since 1.0
     */
    public final void crossover(final Chromosome chromosome1,
                                final Chromosome chromosome2, int k) {
        LOGGER.entering(CLASS_NAME, "crossover",
                        new Object[] { chromosome1, chromosome2, k });

        if (chromosome1.size() < 2) {
            return;
        }
        if (k > chromosome1.size() - 1) {
            throw new IllegalArgumentException("k > chromosome1.size() - 1");
        }
        if (k < 1) {
            throw new IllegalArgumentException("k < 1");
        }

        //Wybierz k losowych punktów krzyżowania.
        List<Integer> kPoints = new ArrayList<Integer>(k);

        RandomUniqueInteger bezPowtorzenZUsuwaniem =
            new RandomUniqueInteger(chromosome1.size()-1);

        for (int i = 0; i < k; i++) {
            kPoints.add(bezPowtorzenZUsuwaniem.get());
        }

        this.crossover(chromosome1, chromosome2, kPoints);

        LOGGER.exiting(CLASS_NAME, "crossover",
                       new Object[] { chromosome1, chromosome2 });
    }

    /**
     * Krzyżowanie.
     * @param chromosome1 Chromosom.
     * @param chromosome2 Chromosom.
     * @param kPoints Lista punktów krzyżowania.
     * np. k{1,4,6,9,10} = x|xxx|xx|xxx|x|x.
     * @since 1.0
     */
    private final void crossover(final Chromosome chromosome1,
                                 final Chromosome chromosome2,
                                 List<Integer> kPoints) {
        LOGGER.entering(CLASS_NAME, "crossover",
                        new Object[] { chromosome1, chromosome2, kPoints });

        //Chromosom nie może być wartością null.
        assert chromosome1 != null : "Illegal argument chromosome1: null";
        assert chromosome2 != null : "Illegal argument chromosome2: null";
        //Lista punktów krzyżowania nie może być wartością null.
        assert kPoints != null : "Illegal argument kPoints: null";
      
        Collections.sort(kPoints);

        Object tmpCh;
        boolean s = false;
        for (int i = 0; i < chromosome1.size(); i++) {
            if (s) {
                tmpCh = chromosome1.getGene(i);
                chromosome1.setGene(i, chromosome2.getGene(i));
                chromosome2.setGene(i, tmpCh);
            }
            if (kPoints.size() > 0) {
                if (i == kPoints.get(0) - 1) {
                    s = !s;
                    kPoints.remove(0);
                }
                //jeśli jest ostatnia sekcja i nie trzeba wymieniać genów
                if ((kPoints.size() == 0) && (s==false)) {
                    return;
                }
            }
        }

        LOGGER.exiting(CLASS_NAME, "crossover",
                       new Object[] { chromosome1, chromosome2 });
    }

    /**
     * Ustaw ilość punktów krzyżowania..
     * @param k Ilość punktów krzyżowania.
     * @since 1.0
     */
    public void setK(int k) {
        this.k = k;
    }

    /**
     * Zwraca ilość punktów krzyżowania.
     * @return Ilość punktów krzyżowania.
     * @since 1.0
     */
    public int getK() {
        return this.k;
    }
}