/***********************************************************************
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.Associative_Classification.ClassifierCBA;
import java.util.*;
/**
* Class to store a non-fuzzy rule, together with some necessary information to manage the CBA algorithm.
*
* @author Written by Jesus Alcala (University of Granada) 09/02/2010
* @version 1.0
* @since JDK1.5
*/
public class Rule implements Comparable {
int[] antecedent;
int[] classCasesCovered;
int clas, nAnts, mark;
long time;
ArrayList<Replace> replace;
double conf, supp;
DataBase dataBase;
/**
* <p>
* Copy Constructor
* </p>
* @param r Rule to be copied
*/
public Rule(Rule r) {
this.antecedent = new int[r.antecedent.length];
this.classCasesCovered = new int[r.classCasesCovered.length];
for (int k = 0; k < this.antecedent.length; k++) this.antecedent[k] = r.antecedent[k];
for (int k = 0; k < this.classCasesCovered.length; k++) this.classCasesCovered[k] = r.classCasesCovered[k];
this.replace = new ArrayList<Replace> ();
for (int k = 0; k < r.replace.size(); k++) this.replace.add(r.replace.get(k).clone());
this.clas = r.clas;
this.dataBase = r.dataBase;
this.conf = r.conf;
this.supp = r.supp;
this.nAnts = r.nAnts;
this.mark = r.mark;
this.time = r.time;
}
/**
* <p>
* Parameters Constructor
* </p>
* @param dataBase Set of training data which is necessary to generate a rule
*/
public Rule(DataBase dataBase) {
this.replace = new ArrayList<Replace> ();
this.antecedent = new int[dataBase.numVariables()];
this.classCasesCovered = new int[dataBase.numClasses()];
for (int i = 0; i < this.antecedent.length; i++) this.antecedent[i] = -1; // Don't care
for (int i = 0; i < this.classCasesCovered.length; i++) this.classCasesCovered[i] = 0;
this.clas = -1;
this.dataBase = dataBase;
this.conf = 0.0;
this.supp = 0.0;
this.nAnts = 0;
this.mark = 0;
this.time = 0;
}
/**
* <p>
* Clone Function
* </p>
*/
public Rule clone() {
Rule r = new Rule(this.dataBase);
for (int i = 0; i < this.antecedent.length; i++) r.antecedent[i] = this.antecedent[i];
for (int i = 0; i < this.classCasesCovered.length; i++) r.classCasesCovered[i] = this.classCasesCovered[i];
for (int i = 0; i < this.replace.size(); i++) r.replace.add(this.replace.get(i).clone());
r.clas = this.clas;
r.dataBase = this.dataBase;
r.conf = this.conf;
r.supp = this.supp;
r.nAnts = this.nAnts;
r.mark = this.mark;
r.time = this.time;
return (r);
}
/**
* <p>
* It sets the rule's antecedent
* </p>
* @param antecedent Array of values. Each position in the array represents an attribute.
*/
public void asignaAntecedente(int [] antecedent){
this.nAnts = 0;
for (int i = 0; i < antecedent.length; i++) {
this.antecedent[i] = antecedent[i];
if (this.antecedent[i] > -1) this.nAnts++;
}
}
/**
* <p>
* It returns the rule's consequent
* </p>
* @param clas Consequent of the rule
*/
public void setConsequent(int clas) {
this.clas = clas;
}
/**
* <p>
* Function to check if a given example matchs with the rule (the rule correctly classifies it)
* </p>
* @param example Example to be classified
* @return double 0.0 = doesn't match, >0.0 = does.
*/
public double matching(int[] example) {
return (this.degree(example));
}
private double degree(int[] example) {
double degree;
degree = 1.0;
for (int i = 0; i < antecedent.length && degree > 0.0; i++) {
degree *= (double) dataBase.matching(i, antecedent[i], example[i]);
}
return (degree);
}
/**
* <p>
* Function to add a replace entry in the "Replace" list
* </p>
* @param r Element to be inserted
*/
public void addReplace(Replace r) {
this.replace.add(r);;
}
/**
* <p>
* Function to check if a rule is equal to another given
* </p>
* @param rule Rule to compare with ours
* @return boolean true = they are equal, false = they aren't.
*/
public boolean isEqual (Rule rule) {
int i;
if (this.clas != rule.getClas()) return (false);
for (i=0; i < this.antecedent.length; i++)
if (this.antecedent[i] != rule.antecedent[i]) return (false);
return (true);
}
/**
* <p>
* It sets the rule's confidence
* </p>
* @param conf double Confidence to be set
*/
public void setConfidence(double conf) {
this.conf = conf;
}
/**
* <p>
* It sets the rule's support
* </p>
* @param supp Support to be set
*/
public void setSupport(double supp) {
this.supp = supp;
}
/**
* <p>
* It sets the rule's mark
* </p>
* @param mark Whether the rule is marked (1) or not (0)
*/
public void setMark (int mark) {
this.mark = mark;
}
/**
* <p>
* It returns the confidence of the rule
* </p>
* @return double Confidence of the rule
*/
public double getConfidence() {
return (this.conf);
}
/**
* <p>
* It returns the Support of the rule
* </p>
* @return double Support of the rule
*/
public double getSupport() {
return (this.supp);
}
/**
* <p>
* It returns the output class of the rule
* </p>
* @return int Output class of the rule
*/
public int getClas() {
return (this.clas);
}
/**
* <p>
* It returns the time of the rule
* </p>
* @return long Time the rule has been added to the rule set
*/
public long getTime() {
return (this.time);
}
/**
* <p>
* It sets the time the rule was added to the rule set
* </p>
* @param time long Time to be set
*/
public void setTime(long time) {
this.time = time;
}
/**
* <p>
* It returns the mark of the rule
* </p>
* @return int 1 = rule is marked, 0 = rule isn't.
*/
public int getMark() {
return (this.mark);
}
/**
* <p>
* Function to mark the rule
* </p>
*/
public void onMark() {
this.mark = 1;
}
/**
* Function to unmark the rule
*/
public void offMark() {
this.mark = 0;
}
/**
* <p>
* It returns the size of the Replace list in the rule
* </p>
* @return int Size of the Replace list in the rule
*/
public int getnReplace() {
return (this.replace.size());
}
/**
* <p>
* It returns the Replace element of the rule in the position "pos"
* </p>
* @param pos Position of the "replace element" we are looking for
* @return Replace Replace element of the rule in the position "pos"
*/
public Replace getReplace(int pos) {
return (this.replace.get(pos));
}
/**
* <p>
* It returns if the rule is marked
* </p>
* @return boolean true = Rule is marked, false = rule is not.
*/
public boolean isMark() {
return (this.mark == 1);
}
/**
* <p>
* Function to know whether our rule has more precedence than another given or not.
* </p>
* @param r Given rule to compare
* @return boolean true = our rule has more precedence, false = it hasn't.
*/
public boolean isPrecedence(Rule r) {
if (this.conf > r.conf) return (true);
else if (this.conf < r.conf) return (false);
if (this.supp > r.supp) return (true);
else if (this.supp < r.supp) return (false);
if (this.time < r.time) return (true);
else if (this.time > r.time) return (false);
return (true);
}
/**
* <p>
* Function to increase in 1 the number of examples whose output class is the given class "clas" and are covered by this rule
* </p>
* @param clas Output class of the covered example
*/
public void incrCovered (int clas) {
this.classCasesCovered[clas]++;
}
/**
* <p>
* Function to decrease in 1 the number of examples whose output class is the given class "clas" and are covered by this rule
* </p>
* @param clas Output class of the covered example
*/
public void decrCovered (int clas) {
this.classCasesCovered[clas]--;
}
/**
* <p>
* It returns the number of examples covered by the rule for the class "class"
* </p>
* @param clas Class to know how many examples with this class are covered by our rule
* @return int Number of examples covered by our rule for the given class
*/
public int getclassCasesCovered (int clas) {
return (this.classCasesCovered[clas]);
}
/**
* <p>
* Function to check whether our rule is subset of a given rule "a"
* </p>
* @param a Given rule to compare
* @return boolean true = our rule is subset of a, false = it isn't.
*/
public boolean isSubset(Rule a) {
if ((this.clas != a.clas) || (this.nAnts > a.nAnts)) return (false);
else {
for (int k = 0; k < this.antecedent.length; k++) {
if (this.antecedent[k] > -1) {
if (this.antecedent[k] != a.antecedent[k]) return (false);
}
}
return (true);
}
}
/**
* It sets the label for a given position in the antecedent (for a given attribute)
* @param pos Location of the attribute which we want to set the label
* @param label New label value to set
*/
public void setLabel(int pos, int label) {
if ((antecedent[pos] < 0) && (label > -1)) this.nAnts++;
if ((antecedent[pos] > -1) && (label < 0)) this.nAnts--;
this.antecedent[pos] = label;
}
/**
* Function to compare objects of the Rule class
* Necessary to be able to use "sort" function
* It sorts in an decreasing order of confidence
* If equals, in an decreasing order of support
* If equals, in an decreasing order of time
*/
public int compareTo(Object a) {
if (((Rule) a).conf < this.conf) return -1;
else if (((Rule) a).conf > this.conf) return 1;
if (((Rule) a).supp < this.supp) return -1;
else if (((Rule) a).supp > this.supp) return 1;
if (((Rule) a).time < this.time) return 1;
else if (((Rule) a).time > this.time) return -1;
return 0;
}
}