Chromosome.java

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

import com.delhezi.ga.exception.GeneticAlgorithmException;
import com.delhezi.ga.mutation.IMutation;
import java.util.logging.Logger;

/**
 * <code>Chromosome</code>: Klasa chromosomu.
 * @param <GENE_TYPE> typ obiektu charakteryzujący gen np.: Integer, Double,
 * lub objekt klasy com.delhezi.genes.*.
 * Uwaga; Genami nie mogą być typy proste np. int, double.
 * @version 1.0 2009-06-10
 * @author <a href="mailto:wojciech.wolszczak@delhezi.com">
 * Wojciech Wolszczak</a>
 */
public class Chromosome<GENE_TYPE> implements Cloneable,
                                   Comparable<Chromosome<GENE_TYPE>> {
    /** Logger object. */
    private static final Logger LOGGER =
        Logger.getLogger(Chromosome.class.getName());

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

    /**
     * Konstruktor.
     * @param genes Tablica genów.
     * @param chromosomeProperties Referencja do obiektu przechowującego
     * parametry wspólne dla wszystkich chromosomów w ramach jednej
     * instancji populacji.
     * @since 1.0
     */
    public Chromosome(final GENE_TYPE[] genes,
                      final ChromosomeProperties chromosomeProperties) {
        //W konstruktorze i metodzie clone inicjuj bezposrednio
        //wartości zmiennych lub wywołuj tylko metody final.
        this.genes = genes;
        this.chProperties = chromosomeProperties;
        this.changed = true;
    }

    /**
     * Porównanie dwóch chromosomów;
     * if x.compareTo(y) == 1 to x jest lepszy niż y.
     * Wykorzystywane przy sortowaniu.
     * UWAGA. LISTA POSORTOWANA JEST W ODWROTNEJ KOLEJNOŚCI
     * CHYAB JAKIŚ BŁĄD W JAVA
     * @param chromosome Chromosom do porównania.
     * @return 0 jeśli wartości wskażników przystosowania chromosomów
     * porównywanych są równe, 1 lub -1  jeśli jeden większy od drugiego.
     */
    public final int compareTo(final Chromosome<GENE_TYPE> chromosome) {
        try {
            if (this.chProperties.getFitnessFunction().isMaximisation() == true) {
                if (this.getFitness() > chromosome.getFitness()) {
                    return 1;
                }
                if (this.getFitness() < chromosome.getFitness()) {
                    return -1;
                }
            } else {
                if (this.getFitness() < chromosome.getFitness()) {
                    return 1;
                }
                if (this.getFitness() > chromosome.getFitness()) {
                    return -1;
                }
            }
        } catch (GeneticAlgorithmException e) {
        }
        return 0; //Chromosomy są równe.
    }


    /**
     * Zwraca parametr określający maksymalizację/minimalizację funkcji
     * celu.
     * @return true -  maksymalizacja funkcji celu (najlepszym jest osobnik o
     *                 najwiekszej wartości wskaźnika przystosowania)
     *         false - minimalizacja funkcji celu (najlepszym jest osobnik o
     *                 najmniejszej wartości wskaźnika przystosowania)
     */
    public final boolean isFitnessMaximisation() {
        return this.chProperties.getFitnessFunction().isMaximisation();
    }


    /**
     * Mutacja.
     * @param mutation Funkcja mutacji
     * @since 1.0
     */
  public final void mutation(final IMutation mutation) {
      mutation.mutation(this);
      //this.changed=true; Infomacja o zmianie chromosomu
                           //ustawiana w funkcji mutation.mutation(..)
  }

  /**
   * Zwraca ilość genów w chromosomie.
   * @return Ilość genów w chromosomie.
   * @since 1.0
   */
  public final int size() {
      if (this.genes == null) {
        return 0;
      } else {
        return this.genes.length;
      }
  }

  /**
   * Wylicza  i zwraca wartość wskaźnika przystosowania.
   * @return Wartość wskaźnika przystosowania.
   * @throws GeneticAlgorithmException xxx
   * @since 1.0
   */
  public final double getFitness() throws GeneticAlgorithmException {
      if (this.changed == true) {
          this.fitness = this.chProperties.getFitnessFunction()
              .calculateFitness(genes);
          this.changed = false;
      }
      return this.fitness;
  }

  /**
   * Funkcja zmienia status chromosomu na "zmodyfikowany";
   * Status chromosomu należy zmienić po operacjach:
   * - bezpośrednio na tabeli genów po uzyskaniu referencji
   * do tabeli, jeśli zmiana odbyła się z pominięciem
   * funkcji setGenes() lub setGene();
   * - przy zmianie referencji do IMutation, jeśli zmiana
   * odbyła się z pominięciem funkcji setMutation();
   * - przy zmianie referencji do IFitnessFunction, jeśli zmiana
   * odbyła się z pominięciem funkcji setFitnessFunction().
   */
  public final void changed() {
      this.changed = true;
  }

  /**
   * Zwraca gen ze wskazanej pozycji (locus).
   * @param locus Pozycja genu (locus).
   * @return Gen określonego typu.
   *
   * @since 1.0
   */
  public final GENE_TYPE getGene(final int locus) {
          return this.genes[locus];
  }

  /**
   * Wstawia gen na wskazaną pozycję (locus).
   * @param locus Locus pod którym ma być wstawiony gen.
   * @param gene Wstawiany gen określonego typu.
   *
   * @since 1.0
   */
  public final void setGene(final int locus, final GENE_TYPE gene) {
          this.genes[locus] = gene;
          this.changed = true;
  }

  /**
   * Zwraca referencję do tablicy genów;
   * Uwaga;
   * Zwracana jest referencja do tablicy a nie jej kopia;
   * Jeśli za pomocą otrzymanej referencji dojdzie do modyfikacji wartości
   * tablicy należy wykonać funkcję changed() klasy Chromosome w celu
   * ponownego wyznaczenia wskaźnika przystosowania chromosomu.
   * @return Referencja do tablicy genów.
   *
   * @since 1.0
   */
  public final GENE_TYPE[] getGenes() {
          return this.genes;
  }

  /**
   * Wstawia referencję do tablicy genów;
   * Uwaga;
   * Wstawiana jest referencja do tablicy a nie jej kopia;
   * Jeśli po wstawieniu referencji dojdzie do modyfikacji watrości
   * tablicy należy wykonać funkcję changed() klasy Chromosome w celu
   * ponownego wyznaczenia wskaźnika przystosowania chromosomu.
   * @param genes Referencja do tablicy genów.
   *
   * @since 1.0
   */
  public final void setGenes(final GENE_TYPE[] genes) {
          this.genes = genes;
          this.changed = true;
  }

  /**
   * Kopiuje chromosom. Ze względu na konieczność skopiowania tablicy
   * genów wymagane jest "głębokie kopiowanie";
   *
   * SPITOLONA FUNCKJA WYMAGA UOGÓLNIENIA DO PRZERÓBKI;
   *
   * @return Głęboka kopia chromosomu.
   * @since 1.0
   */
  @Override
  public final Chromosome<GENE_TYPE> clone() {
      try {
          //super.clone() - Metoda klasy Object - zapewnia płytkie kopiowanie
          //klasy, kopiuje objekt bit po bicie (kopiuje referencje).
          //UWAGA w przypadku kiedy klasa zawiera referencje do objektów
          //ZMIENIALNYCH (np. Date, lub w przypadku tablicy skopiuje się
          //tylko refencja do tablicy) bo kopiowane są referecnje
          //do objektów.
          //W przypadku kiedy klasa zawiera referencje do obiektów
          //NIEZMIENIALNYCH typu String lub Integer nie ma to znaczenia.
          //W przypadku typów prostych - kopiowane sa wartości.
          Chromosome result = (Chromosome<GENE_TYPE>) super.clone();

          //Wsytarczy płytkie kopiowanie bo tablica chromosomów jest pusta.
          if (genes.length < 1) {
              return result;
          }

          //Wymagane GLEBOKIE kopiowanie.
          //Ze względu na możliwe mutacje objekt gene jest ZMIENIALY.
          if (genes[0] instanceof Cloneable) {
          result.genes = new Object[genes.length];
          for (int i = 0; i < genes.length; i++) {
              //if(((String) genes.getClass().getName()).equals(
              //"[Lcom.delhezi.ga.genes.KlasaObjektu;"))
              ////result.genes[i]=((KlasaObjektu) genes[i]).clone();

              //TU TRZEBA DOPISAĆ KOD
              }
          } else {
              result.genes.clone(); //Zakładamy, że elementami tablicy są
                                    //objekty NIEZMIENIALNE.
             //Wystarczy tylko skopiować referencje do nich.
          }

          return result;
      } catch (CloneNotSupportedException ex) {
          throw new AssertionError(); //Błąd JVM.
                                      //Nie powinien się zdarzyć.
      }
  }

  /**
   * String charakteryzujący chromosom.
   * @return String charakteryzujący chromosom.
   * @since 1.0
   */
  @Override
  public final String toString() {
  String str = "CHROMOSOME [fitness=" + this.fitness
               + ", size=" + this.size() + ", genes:";
  for (int i = 0; i < this.size(); i++) {
      str += "[" + this.genes[i].toString() + "]";
      }
  str += "]";
  return str;
  }

  /** Wskaźnik przystosowania. */
  private double fitness;

  /** Tablica genów składająca się na pojedynczy chromosom. */
  private GENE_TYPE[] genes;

  /** Parametr określający, czy geny w chromosomie zostały zmienione. */
  private boolean changed = true;

  /**
   * Referencja do obiektu przechowującego parametry wspólne dla
   * wszystkich chromosomów w ramach jednej instancji populacji.
   */
  private ChromosomeProperties chProperties;
}