/*********************************************************************** 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> * <pre> * Represents an alpha-cut for any type of fuzzy number (triangular, trapezoidal and singleton). * * An alpha cut is defined as: * * A_alpha = {x| mu(x) >= alpha} * * Given the fuzzy set A defined over the Universe of the discourse U, and the membership function mu. * * This implementation uses two arrays for the extremes of the support set: * -left[] * -right[] * * and an array for the alpha-cut: * -alpha[] * * * * membership f * 1.0 - --------------------------- * | / \ * | / \ * alpha[1]----------------/ \ * | / \ * | / \ * a - / \ * | / \ * | / \ * alpha[0]----------/ \ * | / \ * | / \ * 0.0 -------|----------|---------------------------|----------|---------- * left[0] left[1] right[1] right[0] <-- Support * * * * Detailed in: * * Zadeh, L. Fuzzy logic, IEEE Computer, 1:83, (1988) * <pre> * </p> * * <p> * @author Written by Luciano S�nchez (University of Oviedo) 23/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 FuzzyAlphaCut extends Fuzzy { // left and right are the extremes of the fuzzy set support, and alpha is the membership threshold. double[] left, right, alpha; /** * <p> * A copy constructor specialized for Triangular Fuzzy Numbers (FuzzyNumberTRIANG). * * </p> * @param b a FuzzyNumberTRIANG object to be copied */ public FuzzyAlphaCut(FuzzyNumberTRIANG b) { left=new double[2]; right=new double[2]; alpha=new double[2]; left[0]=b.left; left[1]=b.center; right[0]=b.right; right[1]=b.center; alpha[0]=0; alpha[1]=1; } /** * <p> * A copy constructor specialized for Fuzzy Intervals (FuzzyInterval). * * </p> * @param b a FuzzyInterval object to be copied */ public FuzzyAlphaCut(FuzzyInterval b) { left=new double[2]; right=new double[2]; alpha=new double[2]; left[0]=b.a; left[1]=b.a; right[0]=b.b; right[1]=b.b; alpha[0]=0; alpha[1]=1; } /** * <p> * A copy constructor specialized for Fuzzy Singleton Sets(FuzzySingleton). * * </p> * @param b is the FuzzySingleton instance to be copied */ public FuzzyAlphaCut(FuzzySingleton b) { left=new double[2]; right=new double[2]; alpha=new double[2]; left[0]=b.center; left[1]=b.center; right[0]=b.center; right[1]=b.center; alpha[0]=0; alpha[1]=1; } /** * <p> * A copy constructor specialized for Fuzzy Alpha Cuts(FuzzyAlphaCut). * * </p> * @param b a FuzzyAlphaCut object to be copied */ public FuzzyAlphaCut(FuzzyAlphaCut b) { left=new double[b.left.length]; for (int i=0;i<left.length;i++) left[i]=b.left[i]; right=new double[b.right.length]; for (int i=0;i<right.length;i++) right[i]=b.right[i]; alpha=new double[b.alpha.length]; for (int i=0;i<alpha.length;i++) alpha[i]=b.alpha[i]; } /** * <p> * Creates and returns a copy of this object. * * </p> * @return a clone of this instance. */ public Fuzzy clone() { return new FuzzyAlphaCut(this); } /** * <p> * Copies the FuzzyAlphaCut parameter over the present instance. * * </p> * @param b a FuzzyAlphaCut object to be copied */ public void set(FuzzyAlphaCut b) { left=new double[b.left.length]; for (int i=0;i<left.length;i++) left[i]=b.left[i]; right=new double[b.right.length]; for (int i=0;i<right.length;i++) right[i]=b.right[i]; alpha=new double[b.alpha.length]; for (int i=0;i<alpha.length;i++) alpha[i]=b.alpha[i]; } /** * <p> * Indicates whether some other object is "equal to" this one. * * </p> * @param B the reference object with which to compare. * @return true if this object is the same as the B argument; false otherwise. */ public boolean equals(Fuzzy B) { if (!(B instanceof FuzzyAlphaCut)) return false; FuzzyAlphaCut b=(FuzzyAlphaCut)B; for (int i=0;i<left.length;i++) if (left[i]!=b.left[i]) return false; for (int i=0;i<right.length;i++) if (right[i]!=b.right[i]) return false; for (int i=0;i<alpha.length;i++) if (alpha[i]!=b.alpha[i]) return false; return true; } /** * <p> * Returns the membership level for the individual x. * * * </p> * @param x the individual which membership is to be calculated. * @return the membership level for individual x. */ public double evaluateMembership(double x) { //if x is out of the support the membership level is 0. if (x<left[0] || x>right[0]) return 0; //else x is in the support so its membership level can be calculated. for (int i=1;i<left.length;i++) { if (x<left[i] || x>right[i]) { if (x<left[i]) { return alpha[i-1]+(alpha[i]-alpha[i-1])*(x-left[i-1])/(left[i]-left[i-1]); } else { return alpha[i-1]+(alpha[i]-alpha[i-1])*(right[i-1]-x)/(right[i-1]-right[i]); } } } return 1; } /** * <p> * Returns the alpha-cut interval (le, ri) for alpha a. * *<pre> * membership f * 1.0 - --------------------------- * | / \ * | / \ * alpha[1]----------------/ \ * | / \ * | / \ * a -------------/-------------------------------------\ * | /| |\ * | / | | \ * alpha[0]----------/ | | \ * | / | | \ * | / | | \ * 0.0 -------|-----+----|--------------------------|-----+----|---------- * left[0] le left[1] right[1] ri right[0] *</pre> * </p> * @param a the alpha value for which the alpha-cut is to be calculated. * @return the alpha-cut(le,ri) interval for alpha a. */ public FuzzyInterval alphaCut(double a) { //if alpha is 0 the alpha-cut interval is the support if (a==0) return support(); //if any of the extremes of the support are out of the limits the alpha-cut interval is the support if (left[0]<NEGATIVEINF || right[0]>POSITIVEINF) return support(); //else for (int i=1;i<left.length;i++) { if (a<alpha[i]) { double f=(a-alpha[i-1])/(alpha[i]-alpha[i-1]); double le=f*(left[i]-left[i-1])+left[i-1]; double ri=f*(right[i]-right[i-1])+right[i-1]; return new FuzzyInterval(le,ri); } } return new FuzzyInterval(left[left.length-1],right[right.length-1]); } /** * <p> * Creates and returns a FuzzyInterval with the extremes of the support set. * * </p> * @return an interval with the extremes of the support set. */ public FuzzyInterval support() { return new FuzzyInterval(left[0],right[0]); } /** * <p> * Returns the sum of the present FuzzyInterval and the parameter x. * * </p> * @param x to be summed. * @return the sum of the present FuzzyAlphaCut and the parameter x. */ public FuzzyAlphaCut sum(FuzzyAlphaCut x) { if (left.length != x.left.length) System.out.println("FuzzyAlphaCut::suma: option not supported"); FuzzyAlphaCut result=new FuzzyAlphaCut(this); for (int i=0;i<left.length;i++) { result.left[i]+=x.left[i]; result.right[i]+=x.right[i]; } return result; } /** * <p> * Returns the subtract of the present FuzzyInterval and the parameter x. * * </p> * @param x to be subtracted. * @return the subtract of the present FuzzyAlphaCut and the parameter x. */ public FuzzyAlphaCut subtract(FuzzyAlphaCut x) { if (left.length != x.left.length) System.out.println("FuzzyAlphaCut::resta: option not supported"); FuzzyAlphaCut result=new FuzzyAlphaCut(this); for (int i=0;i<left.length;i++) { result.left[i]-=x.right[i]; result.right[i]-=x.left[i]; } return result; } /** * <p> * Returns the multiplication of the present FuzzyInterval and the parameter x. * * </p> * @param k to be multiplied. * @return the multiplication of the present FuzzyAlphaCut and the scalar x. */ public FuzzyAlphaCut multiply(double k) { FuzzyAlphaCut result=new FuzzyAlphaCut(this); for (int i=0;i<left.length;i++) { if (k>0) { result.left[i]=left[i]*k; result.right[i]=right[i]*k; } else { result.left[i]=right[i]*k; result.right[i]=left[i]*k; } } return result; } /** * <p> * Returns the multiplication of the present FuzzyInterval and the parameter x. * * </p> * @param x to be multiplied. * @return the multiplication of the present FuzzyAlphaCut and the parameter x. */ public FuzzyAlphaCut multiply(FuzzyAlphaCut x) { if (left.length != x.left.length) System.out.println("FuzzyAlphaCut::producto: option not supported"); FuzzyAlphaCut result=new FuzzyAlphaCut(this); for (int i=0;i<left.length;i++) { double a=result.left[i]*x.left[i]; double max=a, min=a; double b=result.right[i]*x.right[i]; if (max<b) max=b; if (min>b) min=b; double c=result.left[i]*x.right[i]; if (max<c) max=c; if (min>c) min=c; double d=result.right[i]*x.left[i]; if (max<d) max=d; if (min>d) min=d; if (max*min>0) { if (result.left[i]*result.right[i]<0 || x.left[i]*x.right[i]<0) { if (max<0) max=0; else min=0; } } result.left[i]=min; result.right[i]=max; } return result; } /** * <p> * Returns the square root of the present FuzzyInterval. * * </p> * @return the square root of the present FuzzyAlphaCut. */ public FuzzyAlphaCut sqrt() { FuzzyAlphaCut result=new FuzzyAlphaCut(this); for (int i=0;i<left.length;i++) { double a=Math.sqrt(Math.abs(left[i])); double b=Math.sqrt(Math.abs(right[i])); if (a<b) { result.left[i]=a; result.right[i]=b; } else { result.left[i]=b; result.right[i]=a; } if (left[i]*right[i]<0) { result.left[i]=0; } } return result; } /** * <p> * Returns the square of the present FuzzyInterval. * * </p> * @return the square of the present FuzzyAlphaCut. */ public FuzzyAlphaCut sqr() { FuzzyAlphaCut result=new FuzzyAlphaCut(this); for (int i=0;i<left.length;i++) { double a=left[i]*left[i]; double b=right[i]*right[i]; if (a<b) { result.left[i]=a; result.right[i]=b; } else { result.left[i]=b; result.right[i]=a; } if (left[i]*right[i]<0) { result.left[i]=0; } } return result; } /** * <p> * Returns the exponential of the present FuzzyInterval. * * </p> * @return the exponential of the present FuzzyAlphaCut. */ public FuzzyAlphaCut exp() { FuzzyAlphaCut result=new FuzzyAlphaCut(this); for (int i=0;i<left.length;i++) { double le=left[i], ri=right[i]; if (le>30) le=30; if (ri>30) ri=30; double a=Math.exp(le); double b=Math.exp(ri); result.left[i]=a; result.right[i]=b; } return result; } /** * <p> * Returns the logarithm of the present FuzzyInterval. * * </p> * @return the logarithm of the present FuzzyAlphaCut. */ public FuzzyAlphaCut log() { FuzzyAlphaCut result=new FuzzyAlphaCut(this); final double MINIMUM=1.0E-6; final double MINUSINF=Math.log(MINIMUM); for (int i=0;i<left.length;i++) { double a=MINUSINF, b=MINUSINF; if (left[i]>MINIMUM) a=Math.log(left[i]); if (right[i]>MINIMUM) b=Math.log(right[i]); result.left[i]=a; result.right[i]=b; } return result; } /** * <p> * Returns the centroid of the present alpha-cut. * * </p> * @return the centroid of the present FuzzyAlphaCut. */ public double massCentre() { double mass=0; double sumxw=0, a, b, c, d, h, w, xc; c=left[0]; d=right[0]; for (int i=1;i<left.length;i++) { a=left[i]; b=right[i]; h=alpha[i]-alpha[i-1]; w=h/2*(-a+b-c+d); xc=((a-c)*(2*a+c)+3*(a+b)*(b-a)+(d-b)*(2*b+d))/(3*(-a+b-c+d)); c=a; d=b; mass+=w; sumxw+=xc*w; } if (mass==0) { // It's a singleton return left[0]; } else { return sumxw/mass; } } /** * <p> * Returns the average amplitude of a fuzzy set. It halves the nonspecificity. * * </p> */ public void averageAmplitude() { // Halves the nonspecificity for (int i=0;i<left.length;i++) { double c=(left[i]+right[i])/2; double m=right[i]-c; left[i]=c-m/2; right[i]=c+m/2; } } /** * <p> * Returns the linear combination of two alpha-cuts a and b with alpha "alphap". * * linear_combination = alphap * a + (1-alphap) * b * * </p> * @param a * @param b * @param alphap */ public void linearComb(FuzzyAlphaCut a,FuzzyAlphaCut b,double alphap) { // Linear combination of 'a' and 'b' left=new double[b.left.length]; for (int i=0;i<left.length;i++) left[i]=a.left[i]*alphap+b.left[i]*(1-alphap); right=new double[b.right.length]; for (int i=0;i<right.length;i++) right[i]=a.right[i]*alphap+b.right[i]*(1-alphap); alpha=new double[b.alpha.length]; for (int i=0;i<alpha.length;i++) alpha[i]=b.alpha[i]; } /** * <p> * Returns a printable version of the instance. * * </p> * @return a String with a printable version of alpha-cut. */ public String aString() { String result="ALFA_CORTES{"; for (int i=0;i<left.length;i++) result+=("["+left[i]+", "+right[i]+"] "); return result+"}"; } }