/***********************************************************************
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/
**********************************************************************/
package keel.Algorithms.UnsupervisedLearning.AssociationRules.IntervalRuleLearning.Alatasetal;
/**
* <p>
* @author Written by Nicol� Flugy Pap� (Politecnico di Milano) 24/03/2009
* @author Modified by Diana Mart�n (dmartin@ceis.cujae.edu.cu)
* @version 1.0
* @since JDK1.6
* </p>
*/
import java.util.ArrayList;
import org.core.Randomize;
public class Chromosome implements Comparable {
/**
* <p>
* It is used for representing and handling a Chromosome throughout the evolutionary learning
* </p>
*/
private Gene[] genes;
private double fitness;
private double ruleSupport;
private double antecedentSupport;
private double consequentSupport;
private double ruleConfidence;
private double ruleLift;
private double ruleConv;
private double ruleCF;
private double ruleNetconf;
private double ruleYulesQ;
private ArrayList<Integer> coveredTIDs;
public int nAnts;
/**
* <p>
* It creates a new chromosome by setting up its genes
* </p>
* @param genes The array of genes that the chromosome must handle
*/
public Chromosome(Gene[] genes) {
this.genes = new Gene[genes.length];
for (int i=0; i < genes.length; i++)
this.genes[i] = genes[i].copy();
this.coveredTIDs = new ArrayList<Integer>();
this.nAnts = 0;
for (int i=0; i < genes.length; i++) {
this.genes[i] = genes[i].copy();
if (this.genes[i].getActAs() == Gene.ANTECEDENT) this.nAnts++;
}
}
/**
* <p>
* It allows to clone correctly a chromosome
* </p>
* @return A copy of the chromosome
*/
public Chromosome copy() {
Chromosome chromo = new Chromosome(this.genes);
for (int i=0; i < this.coveredTIDs.size(); i++)
chromo.addCoveredTID( this.coveredTIDs.get(i) );
chromo.fitness = this.fitness;
chromo.ruleSupport = this.ruleSupport;
chromo.antecedentSupport = this.antecedentSupport;
chromo.consequentSupport = this.consequentSupport;
chromo.ruleConfidence = this.ruleConfidence;
chromo.ruleLift = this.ruleLift;
chromo.ruleCF = this.ruleCF;
chromo.ruleConv = this.ruleConv;
chromo.ruleNetconf = this.ruleNetconf;
return chromo;
}
/**
* <p>
* It sets the fitness for a chromosome
* </p>
* @param fitness The fitness value of the chromosome
*/
public void setFitness(double fitness) {
this.fitness = fitness;
}
/**
* <p>
* It returns the fitness of a chromosome
* </p>
* @return The fitness value of the chromosome
*/
public double getFitness() {
return this.fitness;
}
/**
* <p>
* It sets the support of the association rule represented by a chromosome
* </p>
* @param ruleSupport The value representing the rule support
*/
public void setRuleSupport(double ruleSupport) {
this.ruleSupport = ruleSupport;
}
/**
* <p>
* It returns the support of the association rule represented by a chromosome
* </p>
* @return A value representing the rule support
*/
public double getRuleSupport() {
return this.ruleSupport;
}
/**
* <p>
* It sets the confidence of the association rule represented by a chromosome
* </p>
* @param ruleConfidence The value representing the rule confidence
*/
public void setRuleConfidence(double ruleConfidence) {
this.ruleConfidence = ruleConfidence;
}
/**
* <p>
* It returns the confidence of the association rule represented by a chromosome
* </p>
* @return A value representing the rule confidence
*/
public double getRuleConfidence() {
return this.ruleConfidence;
}
/**
* <p>
* It returns the genes of a chromosome
* </p>
* @return An array of genes for the chromosome being considered
*/
public Gene[] getGenes() {
return this.genes;
}
/**
* <p>
* It returns the "i-th" gene of a chromosome
* </p>
* @param i The index of the gene
* @return The "i-th" gene of the chromosome being considered
*/
public Gene getGene(int i) {
return this.genes[i];
}
/**
* <p>
* It indicates the genes which are involved to form an association rule later
* </p>
* @return An array of IDs for the involved genes
*/
public ArrayList<Integer> getIndexOfInvolvedGenes() {
ArrayList<Integer> indexes = new ArrayList<Integer>();
for (int i=0; i < this.genes.length; i++)
if ( this.genes[i].getActAs() != Gene.NOT_INVOLVED ) indexes.add(i);
return indexes;
}
/**
* <p>
* It indicates the genes which are excluded to form an association rule later
* </p>
* @return An array of IDs for the excluded genes
*/
public ArrayList<Integer> getIndexOfNotInvolvedGenes() {
ArrayList<Integer> indexes = new ArrayList<Integer>();
for (int i=0; i < this.genes.length; i++)
if ( this.genes[i].getActAs() == Gene.NOT_INVOLVED ) indexes.add(i);
return indexes;
}
/**
* <p>
* It indicates the genes which act as antecedents within a chromosome
* </p>
* @return An array of IDs for the genes acting as antecedents
*/
public ArrayList<Integer> getIndexOfAntecedentGenes() {
ArrayList<Integer> indexes = new ArrayList<Integer>();
for (int i=0; i < this.genes.length; i++)
if ( this.genes[i].getActAs() == Gene.ANTECEDENT ) indexes.add(i);
return indexes;
}
/**
* <p>
* It indicates the genes which act as consequents within a chromosome
* </p>
* @return An array of IDs for the genes acting as consequents
*/
public ArrayList<Integer> getIndexOfConsequentGenes() {
ArrayList<Integer> indexes = new ArrayList<Integer>();
for (int i=0; i < this.genes.length; i++)
if ( this.genes[i].getActAs() == Gene.CONSEQUENT ) indexes.add(i);
return indexes;
}
/**
* <p>
* It adds a dataset records to the list of records being covered by a chromosome
* </p>
* @param tid The ID of the covered record in the dataset
*/
public void addCoveredTID(int tid) {
this.coveredTIDs.add(tid);
}
/**
* <p>
* It indicates the dataset records which have been covered by a chromosome
* </p>
* @return An array of IDs representing the covered records in the dataset
*/
public ArrayList<Integer> getCoveredTIDs() {
return this.coveredTIDs;
}
/**
* <p>
* It checks whether a chromosome always contains at least one antecedent gene as well as at least one consequent gene.
* If not, it forces this constraint by randomly altering some of its genes
* </p>
*/
public void forceConsistency() {
int n_not_involved, n_ant, n_cons, g_ant, g_cons;
ArrayList<Integer> not_involved_attrs;
not_involved_attrs = this.getIndexOfNotInvolvedGenes();
n_not_involved = not_involved_attrs.size();
n_ant = this.getIndexOfAntecedentGenes().size();
n_cons = this.getIndexOfConsequentGenes().size();
if (n_ant == 0) {
if (n_cons > 0) {
if (n_not_involved == 0) {
g_ant = Randomize.Randint(0, this.genes.length);
this.genes[g_ant].setActAs(Gene.ANTECEDENT);
}
else {
g_ant = not_involved_attrs.get( Randomize.Randint(0, n_not_involved) );
this.genes[g_ant].setActAs(Gene.ANTECEDENT);
}
}
else {
g_ant = Randomize.Randint(0, this.genes.length);
do {
g_cons = Randomize.Randint(0, this.genes.length);
}
while (g_cons == g_ant);
this.genes[g_ant].setActAs(Gene.ANTECEDENT);
this.genes[g_cons].setActAs(Gene.CONSEQUENT);
}
}
else {
if (n_cons == 0) {
if (n_not_involved == 0) {
g_cons = Randomize.Randint(0, this.genes.length);
this.genes[g_cons].setActAs(Gene.CONSEQUENT);
}
else {
g_cons = not_involved_attrs.get( Randomize.Randint(0, n_not_involved) );
this.genes[g_cons].setActAs(Gene.CONSEQUENT);
}
}
}
}
/**
* <p>
* It compares a chromosome with another one in order to accomplish ordering later.
* The comparison is achieved by only considering fitness values.
* For this reason, note that this method provides a natural ordering that is inconsistent with equals
* </p>
* @param obj The object to be compared
* @return A negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object
*/
public int compareTo(Object chr) {
if (((Chromosome) chr).fitness < this.fitness) return -1;
else if (((Chromosome) chr).fitness > this.fitness) return 1;
return 0;
}
/**
* <p>
* It indicates whether some other chromosome is "equal to" this one
* </p>
* @param obj The reference object with which to compare
* @return True if this chromosome is the same as the argument; False otherwise
*/
/*public boolean equals(Object obj) {
Chromosome chr = (Chromosome)obj;
boolean ok = true;
for (int i=0; i < this.genes.length && ok; i++)
if ( ! chr.genes[i].equals( this.genes[i] ) ) ok = false;
return ok;
}
*/
public boolean equals(Chromosome chr) {
int i;
for (i=0; i < this.genes.length; i++) {
if ((this.genes[i].getActAs() != Gene.NOT_INVOLVED) && (chr.genes[i].getActAs() == Gene.NOT_INVOLVED)) return (false);
if ((this.genes[i].getActAs() == Gene.NOT_INVOLVED) && (chr.genes[i].getActAs() != Gene.NOT_INVOLVED)) return (false);
if ((this.genes[i].getActAs() != Gene.NOT_INVOLVED) && (chr.genes[i].getActAs() != Gene.NOT_INVOLVED)) {
if (!chr.genes[i].equals(this.genes[i])) {
return (false);
}
}
}
return (true);
}
/**
* <p>
* It returns a string representation of a chromosome
* </p>
* @return A string representation of the chromosome
*/
public String toString() {
String str = "Fitness: " + this.fitness + "; Rule Support: " + this.ruleSupport + "; Rule Confidence: " + this.ruleConfidence + "\n" ;
for (int i=0; i < this.genes.length; i++)
str += this.genes[i] + "\n";
str += "Covered TIDs: " + this.coveredTIDs;
return str;
}
public double getRuleLift() {
return ruleLift;
}
public void setRuleLift(double ruleLift) {
this.ruleLift = ruleLift;
}
public double getRuleCF() {
return ruleCF;
}
public void setRuleCF(double ruleCF) {
this.ruleCF = ruleCF;
}
public double getRuleConv() {
return ruleConv;
}
public void setRuleConv(double ruleConv) {
this.ruleConv = ruleConv;
}
public double getRuleNetconf() {
return ruleNetconf;
}
public void setRuleNetconf(double ruleNetconf) {
this.ruleNetconf = ruleNetconf;
}
public double getAntecedentSupport() {
return antecedentSupport;
}
public void setAntecedentSupport(double antecedentSupport) {
this.antecedentSupport = antecedentSupport;
}
public double getConsequentSupport() {
return consequentSupport;
}
public void setConsequentSupport(double consequentSupport) {
this.consequentSupport = consequentSupport;
}
public double getRuleYulesQ() {
return ruleYulesQ;
}
public void setRuleYulesQ(double ruleYulesQ) {
this.ruleYulesQ = ruleYulesQ;
}
public int getnAnts() {
return nAnts;
}
public void setnAnts(int ants) {
nAnts = ants;
}
public boolean isSubChromo (Chromosome chromo2) {
int i;
Gene gen;
if (this.getRuleSupport() < chromo2.getRuleSupport()) return (false);
for (i=0; i < genes.length; i++) {
gen = chromo2.getGene(i);
if ((genes[i].getActAs() != Gene.NOT_INVOLVED) && (gen.getActAs() == Gene.NOT_INVOLVED)) return (false);
if ((genes[i].getActAs() == Gene.NOT_INVOLVED) && (gen.getActAs() != Gene.NOT_INVOLVED)) return (false);
if ((genes[i].getActAs() != Gene.NOT_INVOLVED) && (gen.getActAs() != Gene.NOT_INVOLVED)) {
if (!genes[i].isSubGen(gen)) return (false);
}
}
return (true);
}
}