/***********************************************************************
This file is part of KEEL-software, the Data Mining tool for regression,
classification, clustering, pattern mining and so on.
Copyright (C) 2004-2010
F. Herrera (herrera@decsai.ugr.es)
L. S�nchez (luciano@uniovi.es)
J. Alcal�-Fdez (jalcala@decsai.ugr.es)
S. Garc�a (sglopez@ujaen.es)
A. Fern�ndez (alberto.fernandez@ujaen.es)
J. Luengo (julianlm@decsai.ugr.es)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/
**********************************************************************/
/**
* <p>
* @author Written by Juli�n Luengo Mart�n 15/02/2007
* @version 0.1
* @since JDK 1.5
* </p>
*/
package keel.Algorithms.Genetic_Rule_Learning.CORE;
import keel.Dataset.*;
import java.util.*;
import org.core.*;
/**
* <p>
* This class represents the chromosome (rule) of the CORE algorithm
* </p>
*/
public class Chromosome implements Comparable{
// ArrayList<Gene> chrom;
Gene []chrom;
int numGenes;
int _class;
int capturedTokens;
double fitness;
long Mu_next;
boolean evaluated;
/**
* <p>
* Default constructor. No memory allocated.
* </p>
*/
public Chromosome(){
// chrom = new ArrayList<Gene>(Attributes.getInputNumAttributes());
chrom = new Gene[Attributes.getInputNumAttributes()];
evaluated = false;
fitness = -1;
Mu_next = 0;
_class = -1;
numGenes = 0;
capturedTokens = 0;
}
/**
* <p>
* Deep-copy constructor.
* </p>
* @param c original chromosome
*/
public Chromosome(Chromosome c){
chrom = new Gene[Attributes.getInputNumAttributes()];
for(int i=0;i<chrom.length;i++){
if(c.chrom[i] != null)
this.chrom[i] = new Gene(c.chrom[i]);
else
this.chrom[i] = null;
}
evaluated = c.evaluated;
fitness = c.fitness;
Mu_next = c.Mu_next;
_class = c._class;
numGenes = c.numGenes;
capturedTokens = c.capturedTokens;
}
/**
* <p>
* Adds a nominal gene to this chromosome (rule)
* </p>
* @param pos Position in which we put the gene
* @param a the attribute related to this gene (nominal!)
* @param relation the type of the relation which implements the gene (see Gene.java)
* @param values the nominal values that covers this gene
*/
public void addNominalGene(int pos, Attribute a,int relation,ArrayList<String> values){
Gene newGene = new Gene(a,relation);
newGene.addNominalValues(values);
chrom[pos] = newGene;
numGenes++;
}
/**
* <p>
* Adds a real valued gene
* </p>
* @param pos Position in which we put the gene
* @param a the attribute related to this gene (real or integer!)
* @param relation the type of the relation which implements the gene (see Gene.java)
* @param value the real values that covers this gene
*/
public void addRealGene(int pos,Attribute a, int relation, double value){
Gene newGene = new Gene(a,relation);
newGene.setRealValue(value);
chrom[pos] = newGene;
numGenes++;
}
/**
* <p>
* Adds a real-valued gene, and sets its bounds
* </p>
* @param pos the position of the gene in the chromosome
* @param a the attribute related to this gene (real!)
* @param relation the type of relation (see Gene.java)
* @param value array of 2 positions, with the minimum bound (position [0]) and maximum bound (position [1])
*/
public void addRealBoundedGene(int pos,Attribute a, int relation, double value[]){
Gene newGene = new Gene(a,relation);
newGene.setRealminBound(value[0]);
newGene.setRealmaxBound(value[1]);
chrom[pos] = newGene;
numGenes++;
}
/**
* <p>
* Deletes one gene from the chromosome
* </p>
* @param index position of the gene to be deleted
*/
public void removeGene(int index){
chrom[index] = null;
numGenes--;
}
/**
* <p>
* Remove a specific gene from the chromosome, using the Object.equals()
* method (must be the SAME object with SAME id)
* </p>
* @param gene gene object to be deleted from the chromosome
*/
public void removeGene(Gene gene){
for(int i=0;i<chrom.length;i++){
if(gene.equals(chrom[i])){
chrom[i] = null;
numGenes--;
return;
}
}
}
/**
* <p>
* Evaluates an input example (array of doubles as extracted from KEEL API)
* </p>
* @param input the input instance
* @return the class of this rule if covered, -1 otherwise
*/
public int evaluate(double input[]){
boolean covered = true;
for(int i=0;i<input.length && covered;i++){
if(chrom[i]!=null)
covered = chrom[i].test(input[i]);
}
if(covered)
return _class;
else
return -1;
}
/**
* <p>
* Gets the number of genes of this chromosome
* </p>
* @return the number of genes
*/
public int getNumGenes(){
return numGenes;
}
/**
* <p>
* Applies a random mutation of the specified gene
* </p>
* @param gen index of the gene to be mutated
*/
public void mutateGene(int gen){
int relation;
double bounds[] = new double[2];
double value;
ArrayList<String> values;
Attribute a;
Gene g = chrom[gen];
if(g != null){
if(Randomize.Rand()<0.5)
g.mutate();
else
chrom[gen] = null;
}
else{
a = Attributes.getInputAttribute(gen);
if(Randomize.Rand()<0.5){
if(Attributes.getInputAttribute(gen).getType()==Attribute.NOMINAL){
values = new ArrayList<String>();
for(int i=0;i<a.getNumNominalValues();i++){
if(Randomize.Rand()<0.5)
values.add((String)(a.getNominalValuesList().toArray()[i]));
}
addNominalGene(gen, a, Randomize.Randint(0, 2), values);
}
else{
relation = Randomize.Randint(2, 8);
if(relation==Gene.outOfBound || relation==Gene.inBound){
bounds[0] = Randomize.RanddoubleClosed(a.getMinAttribute(), a.getMaxAttribute());
bounds[1] = Randomize.RanddoubleClosed(a.getMinAttribute(), a.getMaxAttribute());
if(bounds[0]>bounds[1]){
value = bounds[0];
bounds[0] = bounds[1];
bounds[1] = value;
}
addRealBoundedGene(gen, a, relation, bounds);
}
else{
value = Randomize.RanddoubleClosed(a.getMinAttribute(), a.getMaxAttribute());
addRealGene(gen, a, relation, value);
}
}
}
}
}
/**
* <p>
* Applies a mutation on this chromosome, adding a gene (0.5 prob) or deleting
* one gene (0.5 prob or if this chromosome has genes for all the attributes)
* </p>
*/
public void mutate(){
int selectedGene,relation;
double value;
double bounds[] = new double[2];
boolean found;
ArrayList<String> values;
Attribute a;
if(Randomize.Rand()<0.5 || numGenes == Attributes.getInputNumAttributes()){
selectedGene = Randomize.Randint(0, chrom.length);
while(chrom[selectedGene]==null){
selectedGene = (selectedGene+1)%chrom.length;
}
chrom[selectedGene] = null;
numGenes--;
}
else{
selectedGene = Randomize.Randint(0, Attributes.getInputNumAttributes());
do{
found = (chrom[selectedGene]!=null);
if(found)
selectedGene = (selectedGene+1)%Attributes.getInputNumAttributes();
}while(found);
a = Attributes.getInputAttribute(selectedGene);
if(Attributes.getInputAttribute(selectedGene).getType()==Attribute.NOMINAL){
values = new ArrayList<String>();
for(int i=0;i<a.getNumNominalValues();i++){
if(Randomize.Rand()<0.5)
values.add((String)(a.getNominalValuesList().toArray()[i]));
}
this.addNominalGene(selectedGene, a, Randomize.Randint(0, 2), values);
}
else{
relation = Randomize.Randint(2, 8);
if(relation==Gene.outOfBound || relation==Gene.inBound){
bounds[0] = Randomize.RanddoubleClosed(a.getMinAttribute(), a.getMaxAttribute());
bounds[1] = Randomize.RanddoubleClosed(a.getMinAttribute(), a.getMaxAttribute());
if(bounds[0]>bounds[1]){
value = bounds[0];
bounds[0] = bounds[1];
bounds[1] = value;
}
this.addRealBoundedGene(selectedGene, a, relation, bounds);
}
else{
value = Randomize.RanddoubleClosed(a.getMinAttribute(), a.getMaxAttribute());
this.addRealGene(selectedGene, a, relation, value);
}
}
}
}
/**
* <p>
* Sets the class of this chromosome
* </p>
* @param c the new consequent class
*/
public void setClass(int c){
_class = c;
}
/**
* <p>
* Gets the class of this rule
* </p>
* @return the consequent class
*/
public int getClas(){
return _class;
}
/**
* <p>
* Set this chromosome as evaluated (fitness computed for the current set of genes) or not
* </p>
* @param ev the new evaluation status
*/
public void setEvaluated(boolean ev){
evaluated = ev;
}
/**
* <p>
* Gets the evaluation status
* </p>
* @return True if the fitness is correct for this gene set, false otherwise
*/
public boolean isEvaluated(){
return evaluated;
}
/**
* <p>
* Sets the fitness for this rule
* </p>
* @param fit the new fitness
*/
public void setFitness(double fit){
fitness = fit;
}
/**
* <p>
* Reset the count of captured tokens for this rule in the tokens
* competition
* </p>
*/
public void resetTokens(){
capturedTokens = 0;
}
/**
* <p>
* Increases the amount of captured tokens by 1
* </p>
*/
public void tokenCaptured(){
capturedTokens++;
}
/**
* <p>
* Decreases the amount of captured tokens by 1
* </p>
*/
public void tokenLost(){
capturedTokens--;
}
/**
* <p>
* Performs the one-point crossover with other chromosome
* </p>
* @param c the chrosomome to be crossed with
* @param cutpoint the cutpoint of this swapping operation
*/
public void swap(Chromosome c,int cutpoint){
Gene gen;
Chromosome tmp = new Chromosome(c);
Attribute a;
double rnd;
boolean aux;
// cutpoint = Math.min(cutpoint, numGenes);
if(Randomize.Rand()<0.7){
for(int i=0;i<cutpoint;i++){
gen = this.chrom[i];
if(c.chrom[i]!= null && gen==null)
c.numGenes--;
if(c.chrom[i]==null && gen!=null)
c.numGenes++;
c.chrom[i] = gen;
gen = tmp.chrom[i];
if(this.chrom[i]!= null && gen==null)
numGenes--;
if(this.chrom[i]==null && gen!=null)
numGenes++;
this.chrom[i] = gen;
}
}
else{
for(int i=0;i<chrom.length;i++){
if(this.chrom[i]!=null && c.chrom[i]!=null){
a = Attributes.getInputAttribute(i);
if(a.getType()!=Attribute.NOMINAL){
rnd = Randomize.RandClosed();
this.chrom[i].realValue = rnd*this.chrom[i].realValue + (1-rnd)*c.chrom[i].realValue;
c.chrom[i].realValue = rnd*c.chrom[i].realValue + (1-rnd)*this.chrom[i].realValue;
}
else{
rnd = Randomize.Randint(0, a.getNumNominalValues());
for(int v=0;v<rnd;v++){
aux = c.chrom[i].nominalValue[v];
c.chrom[i].nominalValue[v] = this.chrom[i].nominalValue[v];
this.chrom[i].nominalValue[v] = aux;
}
}
}
}
}
// c._class = this._class;
// this._class = tmp._class;
}
public int compareTo(Object o){
Chromosome c = (Chromosome) o;
if(this.fitness < c.fitness)
return -1;
if(this.fitness > c.fitness)
return 1;
return 0;
}
/**
* <p>
* Test if two chromosomes are equals by comparing their values
* </p>
* @param c the chromosome to be compared with
* @return True if they are equals in values, false otherwise
*/
public boolean same(Chromosome c){
for(int i=0;i<chrom.length;i++){
if((chrom[i]==null && c.chrom[i]!= null)||
(chrom[i]!=null && c.chrom[i]== null))
return false;
if((chrom[i]!=null && c.chrom[i]!= null)&&(!chrom[i].same(c.chrom[i])))
return false;
}
return true;
}
}