/*********************************************************************** 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/ **********************************************************************/ /** * * File: Rule.java * * Auxiliary class to repressent rules for the BNGE algorithm * * @author Written by Joaquin Derrac (University of Granada) 8/7/2009 * @version 1.1 * @since JDK1.5 * */ package keel.Algorithms.Hyperrectangles.BNGE; import keel.Dataset.Attribute; public class Rule { private static int size; //attributes of the rule private static boolean isNominal[]; //nominal attributes private static int nValues[]; //different values in nominal attributes private double valueMin[]; //for numeric attributes private double valueMax[]; //for numeric attributes private boolean valueNom[][]; //for nominal attributes private double area; //area of the rule private int output; //output attribute /** * Sets the size of the rule * * @param value Number of attributes of the rule * */ public static void setSize(int value){ size=value; nValues=new int[size]; }//end-method /** * Test which attributes are nominal * * @param inputs Attributes' descriptions * */ public static void setAttributes(Attribute[] inputs){ isNominal=new boolean[size]; for(int i=0;i<size;i++){ if(inputs[i].getType()==Attribute.NOMINAL){ isNominal[i]=true; } else{ isNominal[i]=false; } } }//end-method /** * Sets the number of different values for an attribute * * @param value Number of values * @param pos Index of the attribute * */ public static void setNumValue(int value,int pos){ nValues[pos]=value; }//end-method /** * Default builder. Generates a void rule */ public Rule(){ valueMin=new double[size]; valueMax=new double[size]; valueNom=new boolean[size][]; for(int i=0;i<size;i++){ valueNom[i]=new boolean [nValues[i]]; for(int j=0;j<nValues[i];j++){ valueNom[i][j]=false; } } output=-1; area=0; }//end-method /** * Builder. Generates a rule covering only a point * * @param instance Basic instance * @param out Ouput of the instance */ public Rule(double instance[],int out){ int nomRep; valueMin=new double[size]; valueMax=new double[size]; valueNom=new boolean[size][]; for(int i=0;i<size;i++){ valueNom[i]=new boolean [nValues[i]]; for(int j=0;j<nValues[i];j++){ valueNom[i][j]=false; } } for(int i=0;i<size;i++){ if(isNominal[i]){ nomRep=(int)(instance[i]*(nValues[i]-1)); valueNom[i][nomRep]=true; } else{ valueMax[i]=instance[i]; valueMin[i]=instance[i]; } } output=out; computeArea(); }//end-method /** * Reinitialices a rule, loading it with the contents of a single instance * * @param instance Basic instance * @param out Ouput of the instance */ public void loadRule(double instance[],int out){ int nomRep; for(int i=0;i<size;i++){ if(isNominal[i]){ nomRep=(int)(instance[i]*(nValues[i]-1)); valueNom[i][nomRep]=true; } else{ valueMax[i]=instance[i]; valueMin[i]=instance[i]; } } output=out; computeArea(); }//end-method /** * Computes the area of the rule */ private void computeArea(){ int count; area=0.0; for(int i=0;i<size;i++){ if(isNominal[i]){ count=0; for(int j=0;j<valueNom[i].length;j++){ if(valueNom[i][j]){ count++; } } area+=(double)((double)count/(double)valueNom[i].length); } else{ area+=valueMax[i]-valueMin[i]; } } }//end-method /** * Clone method * * @return A intialized copy of the rule */ @Override public Rule clone(){ Rule clon=new Rule(); for(int i=0;i<size;i++){ if(isNominal[i]){ System.arraycopy(valueNom[i], 0, clon.valueNom[i], 0, nValues[i]); } else{ clon.valueMax[i]=valueMax[i]; clon.valueMin[i]=valueMin[i]; } } clon.output=output; clon.area=area; return clon; }//end-method /** * Equals method * * @param rul Another rule * @return True of both rules are equal. False, if not */ @Override public boolean equals(Object rul) { Rule another=(Rule)rul; boolean isEqual=true; if(output!=another.output){ isEqual=false; } if(area!=another.area){ isEqual=false; } for(int i=0;i<size && isEqual;i++){ if(isNominal[i]){ for(int j=0;j<nValues[i]&& isEqual;j++){ if(valueNom[i][j]!=another.valueNom[i][j]){ isEqual=false; } } } else{ if(valueMin[i]!=another.valueMin[i]){ isEqual=false; } if(valueMax[i]!=another.valueMax[i]){ isEqual=false; } } } return isEqual; }//end-method /** * To String method * * @return A text string representing the contents of the rule */ @Override public String toString() { String text=""; for(int i=0;i<size;i++){ text+="Att"+i+": "; if(isNominal[i]){ for(int j=0;j<nValues[i];j++){ text+=j+","; } } else{ text+=valueMin[i]+"-"; text+=valueMax[i]+" "; } } text+="Output= "+output; text+=" Area: "+area; return text; }//end-method /** * Returns the output class of the rule * * @return Output class of the rule */ public int getOutput(){ return output; }//end-method /** * Returns the area of the rule * * @return Area of the rule */ public double getArea(){ return area; }//end-method /** * Computes the distance between a given instance and the rule. * * @param instance Instance to be tested * * @return Distance computed */ public double distance(double instance[]){ double dist=0.0; double inc; int nomRep; for(int i=0;i<size;i++){ if(isNominal[i]){ nomRep=(int)(instance[i]*(nValues[i]-1)); if(valueNom[i][nomRep]==false){ dist+=1.0; } } else{ if(instance[i]<valueMin[i]){ inc=(valueMin[i]-instance[i]); dist+=(inc*inc); } if(instance[i]>valueMax[i]){ inc=(instance[i]-valueMax[i]); dist+=(inc*inc); } } } return dist; }//end-method /** * Computes the distance between two rules. * * @param another Second rule to be tested * * @return Distance computed */ public double distanceRule(Rule another){ double dist=0.0; int count; double inc; double a,b; for(int i=0;i<size;i++){ if(isNominal[i]){ //compute the proportion of examples which differs count=0; for(int j=0;j<nValues[i];j++){ if(valueNom[i][j]!=another.valueNom[i][j]){ count++; } } inc=(double)((double)count/(double)nValues[i]); } else{ //compute distance between the centroids a=(valueMax[i]-valueMin[i])/2.0; b=(another.valueMax[i]-another.valueMin[i])/2.0; if(a>b){ inc=a-b; } else{ inc=b-a; } } dist+=inc*inc; } return dist; }//end-method /** * Test if two rules are overlapped * * @param another Second rule to test * * @return True if the rules are overlapped. False, if not. */ public boolean overlap(Rule another){ boolean over=true; boolean test; for(int i=0;i<size && over;i++){ if(isNominal[i]){ test=false; for(int j=0;j<nValues[i]&&!test;j++){ if((valueNom[i][j]==true)&&(another.valueNom[i][j]==true)){ test=true; } } if(!test){ over=false; } } else{ test=false; //left overlap if((another.valueMax[i]>=valueMin[i])&&(another.valueMax[i]<=valueMax[i])){ test=true; } else{ //right overlap if((valueMax[i]>=another.valueMin[i])&&(valueMax[i]<=another.valueMax[i])){ test=true; } } if(!test){ over=false; } } } return over; }//end-method /** * Merge two rules * * @param another Second rule to merge */ public void merge(Rule another){ for(int i=0;i<size;i++){ if(isNominal[i]){ for(int j=0;j<nValues[i];j++){ if(another.valueNom[i][j]==true){ valueNom[i][j]=true; } } } else{ if(another.valueMin[i]<valueMin[i]){ valueMin[i]=another.valueMin[i]; } if(another.valueMax[i]>valueMax[i]){ valueMax[i]=another.valueMax[i]; } } } computeArea(); }//end-method }//end-class