/*********************************************************************** 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.Fuzzy_Rule_Learning.Shared.Fuzzy; /** * <p> * Represents a FRBS (Fuzzy Rule Base System). A FRBS is composed of: * * -content: the consequents of the rules (each rule has an index to partition array) * -partitions: the antecedents for each rule. * -partition: the consequents shared by all the rules. * </p> * * <p> * @author Written by Luciano S�nchez (University of Oviedo) 20/01/2004 * @author Modified by Enrique A. de la Cal (University of Oviedo) 13/12/2008 * @version 1.0 * @since JDK1.4 * </p> */ public class RuleBase { // TNorm int tnr; int agr; // The vector of fuzzy rules with their consequent index and weight. FuzzyRule[] content; // The vector of fuzzy partitions with the antecedents for each rule. FuzzyPartition[] partitions; // Fuzzy partition with consequents. FuzzyPartition partition; final static int minimum = 0; public final static int product = 1; final static int maximum = 0; public final static int sum = 1; // Defuzzification by mass center public final static int DEFUZCDM = 0; // Defuzzification by maximum public final static int DEFUZMAX = 1; long[] rules; /** * <p> * A constructor for a RuleBase. * * </p> * @param pe vector of fuzzy partitions with the antecedents for each rule. * @param ps fuzzy partition with consequents for the rules. * @param tn T-Norm for RuleBase. * @param ag . */ public RuleBase(FuzzyPartition[] pe, FuzzyPartition ps, int tn, int ag) { partitions = new FuzzyPartition[pe.length]; for (int i = 0; i < pe.length; i++) partitions[i] = pe[i].clone(); partition = ps.clone(); tnr = tn; agr = ag; int n = 1; // for (int i=0;i<pe.length;i++) n*=pe[i].size(); content = new FuzzyRule[n]; for (int i = 0; i < n; i++) content[i] = new FuzzyRule(); } /** * <p> * A copy constructor for a RuleBase, given other RuleBase. * * </p> * @param b to be copied. */ public RuleBase(RuleBase b) { partitions = new FuzzyPartition[b.partitions.length]; for (int i = 0; i < partitions.length; i++) partitions[i] = b.partitions[i].clone(); partition = b.partition.clone(); tnr = b.tnr; agr = b.agr; content = new FuzzyRule[b.content.length]; for (int i = 0; i < b.content.length; i++) content[i] = b.content[i].clone(); } /** * <p> * Copies the RuleBase parameter over the present instance. * * </p> * @param b a RuleBase object to be copied */ public void set(RuleBase b) { partitions = new FuzzyPartition[b.partitions.length]; for (int i = 0; i < partitions.length; i++) partitions[i] = b.partitions[i].clone(); partition = b.partition.clone(); tnr = b.tnr; agr = b.agr; content = new FuzzyRule[b.content.length]; for (int i = 0; i < b.content.length; i++) content[i] = b.content[i].clone(); } /** * <p> * Creates and returns a copy of this object. * * </p> * @return a clone of this instance. */ public RuleBase clone() { return new RuleBase(this); } /** * <p> * Prints the results. * * </p> */ public void debug() { print(); } /** * <p> * Returns the number of rules. * * </p> */ public int size() { return content.length; } /** * <p> * Returns rule n. * * </p> * @param n the number of rule. */ public FuzzyRule getComponent(int n) { return content[n]; } /** * <p> * Copies a new rule in the RuleBase. * * </p> * @param n the number of rule to rewrite. * @param b the new rule to copy in present RuleBase. */ public void setComponent(int n, FuzzyRule b) { content[n] = b.clone(); } /** * <p> * Returns a vector with indexes corresponding to antecedents labels of example r in vector partitions. * * </p> * @param r the codification of an example to be decoded. */ int[] decodifyRule(long r) { // Now, a vector with indexes corresponding to antecedents labels is // built int[] result = new int[partitions.length]; for (int i = result.length - 1; i >= 0; i--) { result[i] = (int) (r % partitions[i].size()); r /= partitions[i].size(); } return result; } /** * <p> * Returns a String with the antecedents (Vi) of rule r. * * </p> * @param r the number of rule whose antecedents are to be printed. */ public String variableNames(long r) { int[] d = decodifyRule(r); String result = "["; for (int i = 0; i < d.length; i++) { result += "V" + i + "-" + d[i]; if (i != d.length - 1) result += ","; } return result + "]"; } /** * <p> * Returns the T-Norm of two membership values. * * </p> * @param x the membership grade of one individual. * @param y the membership grade of one individual. */ public double tnorm(double x, double y) { if (tnr == minimum) { if (x < y) return x; else return y; } else return x * y; } /** * <p> * Returns the Add-Norm of two membership values. * * </p> * @param x the membership grade of one individual. * @param y the membership grade of one individual. */ double add(double x, double y) { if (agr == maximum) { if (x > y) return x; else return y; } else return x + y; } /** * <p> * Returns Grade of Membership of x to rule r antecedent. * * </p> * @param r a rule index. * @param x individual. */ public double evaluateMembership(long r, double[] x) { int[] d = decodifyRule(r); double pertenencia = 1; for (int j = 0; j < x.length; j++) { pertenencia = tnorm(pertenencia, partitions[j].getComponent(d[j]) .evaluateMembership(x[j])); } return pertenencia; } /** * <p> * Returns output (Wang-Mendel) for input x. * * </p> * @param x individual. */ public double[] output(double[] x) { // It calculates the output WM for input x double[] result = new double[partition.size()]; for (int i = 0; i < content.length; i++) { if (content[i].weight == 0) continue; double p = tnorm(evaluateMembership(i, x), content[i].weight); result[content[i].consequent] = add( result[content[i].consequent], p); } return result; } /** * <p> * Adds new rules to BaseRule. * * </p> * @param rules vector with coded indexes of the rules. * @param rules2 vector with antecedents and weights of the rules. */ public void addRules(long[] rules, FuzzyRule[] rules2) { this.rules = new long[rules.length]; content = new FuzzyRule[rules.length]; for (int i = 0; i < rules.length; i++) { this.rules[i] = rules[i]; content[i] = new FuzzyRule(rules2[i]); } } /** * <p> * Returns output (Wang-Mendel) for input x. * * </p> * @param x individual. * @return a vector with association grade between the example x and the classes of the rules (content[i].consequent) */ public double[] myOutput(double[] x) { // It calculates the output WM for input x double[] result = new double[partition.size()]; for (int i = 0; i < rules.length; i++) { // it's calculated the association grade between rule i and example x double p = tnorm(evaluateMembership(rules[i], x), content[i].weight); // It added the association grade rule-example to certainty grade of the class result[content[i].consequent] = add( result[content[i].consequent], p); // It's calculated the association grade between the example x and the classes (content[i].consequent) } return result; } /** * <p> * Returns the number of consequents in RuleBase. * * </p> */ public int numConsequents() { return partition.size(); } /** * <p> * Prints all the rules in the base. * * </p> */ void print() { // It prints the result System.out.println("Debug RuleBase " + size()); for (int r = 0; r < size(); r++) if (content[r].weight >= 0) System.out.println("IF " + variableNames(r) + " THEN " + "S" + content[r].consequent + " with weight " + content[r].weight); System.out.println("------------"); } /** * <p> * Defuzzifies output using method IDDEFUZZIFY. * * </p> * @param output vector with the output to be defuzzified. * @param IDDEFUZZIFY type of defuzzification to run (RuleBase.DEFUZCDM or RuleBase.DEFUZMAX). */ public double defuzzify(double[] output, int IDDEFUZZIFY) { if (IDDEFUZZIFY == DEFUZCDM) { // Defuzzification by massas center // It calculates a charateristic value from the fuzzy range of // outputs double centerSum = 0, weightSum = 0; for (int i = 0; i < partition.size(); i++) { centerSum += partition.getComponent(i).massCentre() * output[i]; weightSum += output[i]; } if (weightSum == 0) return 0; // Not covered output. return centerSum / weightSum; } if (IDDEFUZZIFY == DEFUZMAX) { // Defuzzification by maximum // It calculates a charateristic value from the fuzzy range of // outputs double val = 0, mumax = 0; for (int i = 0; i < partition.size(); i++) { if (output[i] > mumax) { mumax = output[i]; val = partition.getComponent(i).massCentre(); } } if (mumax == 0) return 0; // Not covered output. return val; } return 0; } /** * <p> * This method finds out the label with maximum membership value for each variable. * After that, it codifies the label indexes with corresponding variable cardinality (or partition cardinality) in a long value. * The codification consists in weighting each label index by the product of previous variables cardinality. * * </p> * @param example input example to codify. * @return the codification of example in terms of the antecedent membership. */ public long codifyAntecents(double[] example) { int[] antecedent = new int[example.length]; for (int i = 0; i < example.length; i++) { // for each input variables in the example double max = 0.0; int etq = 0; for (int j = 0; j < partitions[i].size(); j++) { // for each possible label in variable i double per = partitions[i].getComponent(j).evaluateMembership( example[i]); if (per > max) { max = per; etq = j; } } if (max == 0.0) { System.err.println("Error searching antecedent"); System.err.println("\nExample:"); for (int j = 0; j < example.length; j++) System.err.println("" + example[j] + "\t"); System.err.println("Variable -> " + i); System.exit(1); } antecedent[i] = etq; } long rule = 0, j = 1; for (int i = antecedent.length - 1; i >= 0; j *= partitions[i].size(), i--) { rule += (long) (antecedent[i] * j); } return rule; } }