/*********************************************************************** 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.Random_Sets.FSS98; import org.core.*; /** * <p> * The auxiliary class Cluster supports a cluster region of an individual. * It is used to store a dendogram. * It is intended to be used in the Fuzzy Random Sets Regression Algorithm. * </p> * * <p> * @author Written by Luciano Sanchez (University of Oviedo) 08/03/2003 * @version 1.0 * @since JDK1.4 * </p> */ class Cluster { //The covariance matrix of the cluster double [][]C; // Cluster covariance //The clusters centroids double [][]m; // Mean cluster //The number of centroids int n; // Number of cluster elements //The value of energy of the cluster double e; // Cluster energy //The left-hand sub-tree Cluster leftHandStree; // Left and rigth sub-trees //The right-hand sub-tree Cluster rightHandStree; //The ordinal position of the leaf node int ord; // Ordinal for point if it't a terminal node } class MatrixCalcs { /** * <p> * The auxiliary class MatrixCalcs supports matrixes operations. * It is intended to be used in the Fuzzy Random Sets Regression Algorithm. * </p> */ //Exception in case a Singular Matrix is carry out public static class SingularError extends Exception { SingularError(String reason) { super(reason); } public String toString() { return "Singular Matrix: " +getMessage(); } } //Exception in case two matrixes dimensions do not match public static class DimensionError extends Exception { DimensionError(String reason) { super(reason); } public String toString() { return "Matrixes dimensions do not match: " +getMessage(); } } //The minimum matrix element value protected static final double MINVALPRO=(double)1.0e-10; /** * <p> * This protected static method returns the LU decomposition of an square matrix. * </p> * @param a the matrix for which the LU decomposition will be carried out, it is * a bi-dimensional array of doubles * @param indx the matrix index array, an array of integers for book-keeping the * row interchanges * @return a double value with the determinant of the matrix * @throws ErrorSingula in case of a singular matrix */ protected static double ludcmp(double[][] a,int[] indx) throws SingularError { // Return new values for a, indx, d double d; int n=a[0].length; int i,imax,j,k; double big,dum,sum,temp; double[] vv=new double[n+1]; d=(double)1.0; for (i=1;i<=n;i++) { big=(double)0.0; for (j=1;j<=n;j++) if ((temp=Math.abs(a[j-1][i-1]))>big) big=temp; if (big==0.0) { throw new SingularError("Singular Matrix in ludcmp"); } vv[i-1]=(double)1.0/big; } for (j=1;j<=n;j++) { for (i=1;i<j;i++) { sum=a[j-1][i-1]; for (k=1;k<i;k++) sum -= a[k-1][i-1]*a[j-1][k-1]; a[j-1][i-1]=sum; } big=(double)0.0; imax=-1; for (i=j;i<=n;i++) { sum=a[j-1][i-1]; for (k=1;k<j;k++) sum-=a[k-1][i-1]*a[j-1][k-1]; a[j-1][i-1]=sum; if ((dum=vv[i-1]*Math.abs(sum))>=big) { big=dum; imax=i; } } if (j!=imax) { for (k=1;k<=n;k++) { dum=a[k-1][imax-1]; a[k-1][imax-1]=a[k-1][j-1]; a[k-1][j-1]=dum; } d=-d; vv[imax-1]=vv[j-1]; } indx[j-1]=imax; if (Math.abs(a[j-1][j-1])<MINVALPRO) throw new SingularError("Singula Matrix in ludcmp"); if (j!=n) { dum=(double)1.0/(a[j-1][j-1]); for (i=j+1;i<=n;i++) a[j-1][i-1]*=dum; } } return d; } /** * <p> * This protected static method carries out the LU decomposition with back substitution * of an square matrix. * </p> * @param a the matrix for which the LU decomposition will be carried out, it is * a bi-dimensional array of doubles * @param indx the matrix index array, an array of integers for book-keeping the * row interchanges * @param b the input/output vector, a double array */ protected static void lubksb(double[][] A,int[] indx,double[] b) { int i,ii=0,ip,j,n=A.length; double sum; for (i=1;i<=n;i++) { ip=indx[i-1]; sum=b[ip-1]; b[ip-1]=b[i-1]; if (ii!=0) for (j=ii;j<=i-1;j++) sum-=A[j-1][i-1]*b[j-1]; else if (sum!=0) ii=i; b[i-1]=sum; } for (i=n;i>=1;i--) { sum=b[i-1]; for (j=i+1;j<=n;j++) sum-=A[j-1][i-1]*b[j-1]; b[i-1]=sum/A[i-1][i-1]; } } /** * <p> * This private static method copies one matrix into another. * </p> * @param a the bi-dimensional double array, the destination matrix * @param vA the bi-dimensional double array to be copied */ private static void copy(double[][] A, double[][] vA) { for (int i=0;i<vA.length;i++) for (int j=0;j<vA[i].length;j++) A[i][j]=vA[i][j]; } /** * <p> * This private static method rotates i-j-element with the k-l-element * for a given matrix. * </p> * @param a the bi-dimensional double array, the matrix to be rotated * @param i the integer row index of the first element * @param j the integer column index of the first element * @param k the integer row index of the second element * @param l the integer column index of the second element * @param vA the bi-dimensional double array to be copied * @param s a double, the scale for the rotating operation. * @param tau a double, the rate for the rotating operation. */ private static void rotate(double a[][], int i, int j, int k, int l, double s, double tau) { double g=a[i-1][j-1]; double h=a[k-1][l-1]; a[i-1][j-1]=g-s*(h+g*tau); a[k-1][l-1]=h+s*(g-h*tau); } /** * <p> * This protected static method calculates the jacobian of a given matrix. * </p> * @param a the matrix whose jacobi is to be determined * @param d the integer row index of the first element * @param v the eigenvalues * @param k the integer row index of the second element */ protected static void jacobi(double[][] a, double[] d, double[][] v) { int j,iq,ip,i; double tresh,theta,tau,t,sm,s,h,g,c,b[],z[]; int n=a[0].length; int nrot; b=new double[n]; z=new double[n]; for (ip=1;ip<=n;ip++) { for (iq=1;iq<=n;iq++) v[ip-1][iq-1]=(double)0.0; v[ip-1][ip-1]=(double)1.0; } for (ip=1;ip<=n;ip++) { b[ip-1]=d[ip-1]=a[ip-1][ip-1]; z[ip-1]=(double)0.0; } nrot=0; for (i=1;i<=50;i++) { sm=(double)0.0; for (ip=1;ip<=n-1;ip++) { for (iq=ip+1;iq<=n;iq++) sm+=Math.abs(a[ip-1][iq-1]); } if (sm==(double)0.0) { return; } if (i<4) tresh=(double)0.2*sm/(n*n); else tresh=(double)0.0; for (ip=1;ip<=n-1;ip++) { for (iq=ip+1;iq<=n;iq++) { g=(double)100.0*Math.abs(a[ip-1][iq-1]); if (i>4 && (double)(Math.abs(d[ip-1])+g)== (double)Math.abs(d[ip-1]) && (double)(Math.abs(d[iq-1])+g)== (double)Math.abs(d[iq-1])) a[ip-1][iq-1]=(double)0.0; else if (Math.abs(a[ip-1][iq-1])>tresh) { h=d[iq-1]-d[ip-1]; if ((double)(Math.abs(h)+g)==(double)Math.abs(h)) t=(a[ip-1][iq-1])/h; else { theta=(double)0.5*h/(a[ip-1][iq-1]); t=(double)(1.0/(Math.abs(theta)+Math.sqrt(1.0+theta*theta))); if (theta<(double)0.0) t=-t; } c=(double)(1.0/Math.sqrt(1+t*t)); s=t*c; tau=s/((double)1.0+c); h=t*a[ip-1][iq-1]; z[ip-1]-=h; z[iq-1]+=h; d[ip-1]-=h; d[iq-1]+=h; a[ip-1][iq-1]=(double)0.0; for (j=1;j<=ip-1;j++) { rotate(a,j,ip,j,iq,s,tau); } for (j=ip+1;j<=iq-1;j++) { rotate(a,ip,j,j,iq,s,tau); } for (j=iq+1;j<=n;j++) { rotate(a,ip,j,iq,j,s,tau); } for (j=1;j<=n;j++) { rotate(v,j,ip,j,iq,s,tau); } ++(nrot); } } } for (ip=1;ip<=n;ip++) { b[ip-1]+=z[ip-1]; d[ip-1]=b[ip-1]; z[ip-1]=(double)0.0; } } // change -> exception System.out.println("Demasiadas iteraciones en rutina jacobi"); } // ----------------------------- // INTERFACE CLASS // ----------------------------- // Generate one row matrix from vector /** * <p> * This static method returns one row matrix from a vector * </p> * @param A the vector, an array of double values * @return the bi-dimensional matrix of A as the only row */ public static double[][] oneRowMatrix( double[] A) { double[][] R=new double[1][A.length]; R[0]=A; return R; } // Generate one column matrix from vector /** * <p> * This static method returns one column matrix from a vector * </p> * @param A the vector, an array of double values * @return the bi-dimensional matrix of A as the only column */ public static double[][] oneColumnMatrix( double[] A) { return tr(oneRowMatrix(A)); } // Sum /** * <p> * This static method returns a matrix as the arithmetic sum * of the two matrixes given as parameters * </p> * @param A the first matrix to sum, a bi-dimensional array of doubles * @param B the second matrix to sum, a bi-dimensional array of doubles * @return the bi-dimensional array of doubles, the matrix (A+B) */ public static double[][] matSum( double[][] A, double[][] B) throws DimensionError { int i,j,k; if (A.length!=B.length || A[0].length!=B[0].length) { throw new DimensionError( "A="+A.length+" "+A[0].length+ " B="+B.length+" "+B[0].length); } double[][] C=new double[A.length][A[0].length]; for (i=0;i<C.length;i++) for (j=0;j<C[i].length;j++) C[i][j]=A[i][j]+B[i][j]; return C; } // Dif /** * <p> * This static method returns a matrix as the arithmetic difference * of the two matrixes given as parameters * </p> * @param A the first matrix, a bi-dimensional array of doubles * @param B the second matrix (the minuend), a bi-dimensional array of doubles * @return the bi-dimensional array of doubles, the matrix (A-B) */ public static double[][] matDif( double[][] A, double[][] B) throws DimensionError { int i,j,k; if (A.length!=B.length || A[0].length!=B[0].length) { throw new DimensionError( "A="+A.length+" "+A[0].length+ " B="+B.length+" "+B[0].length); } double[][] C=new double[A.length][A[0].length]; for (i=0;i<C.length;i++) for (j=0;j<C[i].length;j++) C[i][j]=A[i][j]-B[i][j]; return C; } // Mult matrix double /** * <p> * This static method returns a matrix as the arithmetic product of the * given matrixes and a scalar real value. * </p> * @param A the first matrix, a bi-dimensional array of doubles * @param B the scalar real value, a double * @return the bi-dimensional array of doubles, the matrix (A.*B) */ public static double[][] matMul( double[][] A, double k) { int i,j; double[][] C=new double[A.length][A[0].length]; for (i=0;i<C.length;i++) for (j=0;j<C[i].length;j++) C[i][j]=A[i][j]*k; return C; } // Mult /** * <p> * This static method returns a matrix as the arithmetic product of the * two matrixes given as parameters. The dimensions of the matrixes must * match: the number of columns of the first must be equals to the number * of rows of the second. * </p> * @param A the first matrix, a bi-dimensional array of doubles * @param B the second matrix, a bi-dimensional array of doubles * @return the bi-dimensional array of doubles, the matrix (A*B) * @throws DimensionError if the matrixes dimensions do not match */ public static double[][] matMul( double[][] A, double[][] B) throws DimensionError { int i,j,k; if (A[0].length!=B.length) { throw new DimensionError( "A="+A.length+" "+A[0].length+ " B="+B.length+" "+B[0].length); } double[][] C=new double[A.length][B[0].length]; for (i=0;i<C.length;i++) { for (j=0;j<C[i].length;j++) { C[i][j]=0; for (k=0;k<A[0].length;k++) C[i][j]+=A[i][k]*B[k][j]; } } return C; } // Transposed /** * <p> * This static method returns the transpose of a given matrix. * </p> * @param A the matrix to transpose * @return the bi-dimensional array of doubles, the matrix (A*B) */ public static double[][] tr(double[][] A) { int i,j; double[][] R=new double[A[0].length][A.length]; for (i=0;i<R.length;i++) { for (j=0;j<R[i].length;j++) R[i][j]=A[j][i]; } return R; } // Determinant /** * <p> * This static method returns the determinant of a given matrix provided * it is not a Singular Matrix. * </p> * @param A the matrix whose determinant is to be calculated, a * bi-dimensional array of doubles * @return a double value with the determinant of A calculated. * @throws SingularError if the matrix A is singular. */ public static double determinant(double[][] vA) throws SingularError { int N=vA.length; double[][] A = new double[N][N]; copy(A,vA); double[][] Y= new double[N][N]; int [] indx=new int [N]; double[] col=new double[N]; double d = ludcmp(A,indx); for (int j=0;j<N;j++) { d*=A[j][j]; } return d; } // Inverse /** * <p> * This static method returns the inverse of a given matrix provided * it is not a Singular Matrix. * </p> * @param A the matrix whose inverse is to be calculated, a * bi-dimensional array of doubles * @return a bi-dimensional array of double values, the inv(A) * @throws SingularError if the matrix A is singular. */ public static double[][] inv(double[][] vA) throws SingularError { int N=vA.length; double[][] A = new double[N][N]; copy(A,vA); double[][] Y= new double[N][N]; int [] indx=new int [N]; double[] col=new double[N]; double d = ludcmp(A,indx); for (int j=0;j<N;j++) { int i; for (i=0;i<N;i++) col[i]=(double)0.0; col[j]=(double)1.0; lubksb(A,indx,col); for (i=0;i<N;i++) Y[j][i]=col[i]; } return Y; } /** * <p> * This static method returns the inverse of a given matrix provided * it is not a Singular Matrix. If it does, then the method returns * false. * </p> * @param A the matrix whose inverse is to be calculated, a * bi-dimensional array of doubles. Matrix A is modified * in this methods, and at the end, contains the calculated * inverse matrix. * @return true if A is not a Singular Matrix, otherwise it is false */ public static boolean protectedInverse(double[][] A) { int N=A[0].length; int[] indx=new int[N]; double[][] Y=new double[N][N]; double[] col=new double[N]; try { double d=ludcmp(A,indx); } catch(SingularError e) { return true; } for (int j=0;j<N;j++) { int i; for (i=0;i<N;i++) col[i]=(double)0.0; col[j]=(double)1.0; lubksb(A,indx,col); for (i=0;i<N;i++) Y[j][i]=col[i]; } copy(A,Y); return false; } /** * <p> * This static method returns the Identity matrix with dimension nxn * </p> * @param n the dimension of the Identity matrix * @return a bi-dimensional array of double values, the I matrix */ public static double[][] I(int n) { double[][] result=new double[n][n]; for (int i=0;i<n;i++) { for (int j=0;j<n;j++) if (i==j) result[i][i]=1; else result[i][j]=0; } return result; } /** * <p> * This static method calculates the eigenvalues of a given matrix. * </p> * @param A the matrix whose eigenvalues are to be calculated, a * bi-dimensional array of doubles * @param P a bi-dimensional array of dobule values with the * calculated search matrix, P accomplish with * tr(P)=inv(P) and P*D*tr(P)=A * @param D the matrix with the calculated eigenvalues, a * bi-dimensional array of doubles */ public static void getEigenValues(double[][] A, double[][] P, double[][] D) { // Diagonalize matrix // Search matrix P / tr(P)=inv(P) // and P*D*tr(P)=A and D diagonal double[] d=new double[A[0].length]; jacobi(A,d,P); for (int i=0;i<D.length;i++) for (int j=0;j<D[i].length;j++) { if (i==j) D[i][i]=d[i]; else D[i][j]=0; } } /** * <p> * This static method calculates the scalar product of two vectors. * </p> * @param a an array of doubles with the first vector * @param b an array of doubles with the second vector * @return the scalar product of the two vectors as a double value */ public static double dot( double[] a, double[] b) { double result=0; for (int i=0; i<a.length;i++) result+=a[i]*b[i]; return result; } // --------------------- // Code Test // --------------------- /** * <p> * This static method prints out to the standard output a given matrix. * </p> * @param B a bi-dimiensional array of doubles with the matrix to be printed */ protected static void matprn(double [][] B) { for (int i=0;i<B.length;i++) { for (int j=0;j<B[i].length;j++) System.out.print(B[i][j]+" "); System.out.println(); } } /** * <p> * This static method is given to test this class. * </p> * @param argv an array of Strings with the parameters */ public static void main(String argv[]) { try { double[] A=new double[3]; A[0]=1; A[1]=2; A[2]=3; double[][] B=oneRowMatrix(A); double[][] C=matMul(tr(B),B); C[0][0]=7; C[1][1]=13; C[2][2]=19; matprn(C); double [][] D=new double[C.length][C.length]; copy(D,C); boolean b=protectedInverse(D); if (b) System.out.println("La matriz era singular"); matprn(D); double [][] E=matMul(D,C); matprn(E); D=inv(C); E=matMul(D,C); matprn(E); double [][] P=new double[C.length][C.length]; double [][] Diag=new double[C.length][C.length]; getEigenValues(C,P,Diag); matprn(C); matprn(P); matprn(Diag); D=matMul(matMul(P,Diag),tr(P)); matprn(D); } catch(DimensionError e) { System.err.println(e); } catch(SingularError e) { System.err.println(e); } } } /** * <p> * RSFSS is the model to be obtained as the regression model using the * fuzzy random sets regression algorithm. * * Detailed in: * * L. S�nchez. A Random Sets-Based Method for Identifying Fuzzy Models. Fuzzy Sets * and Systems 98:3 (1998) 343-354. * </p> * * <p> * @author Written by Luciano Sanchez (University of Oviedo) 08/03/2003 * @version 1.0 * @since JDK1.4 * </p> */ public class RSFSS { //The input data from the dataset double [][]X; //the output data from the dataset double []Y; //The mean Y in a cluster double []meanY; //The covariance matrix for each cluster double [][][]Covar; //The centres matrix for each cluster found double [][][]centres; //The rule coefficients double [][][]A; //The rule weight double w[]; /** * <p> * This private method clones a given double values array. * </p> * @param x the array of doubles to clone * @return an array of double values, a perfect copy of x. */ private double[] clone(double[] x) { double[] res=new double[x.length]; for (int i=0;i<x.length;i++) res[i]=x[i]; return res; } /** * <p> * This private method copies all the elements in a given * double values array but the last one, which is skipped. * The resultant vector has one dimension less than the * given one. * </p> * @param x the array of doubles to clone * @return an array of double values with all the elements in x except the last one. */ private double[] truncate(double[] x) { double[] res=new double[x.length-1]; for (int i=0;i<res.length;i++) res[i]=x[i]; return res; } /** * <p> * This private method copies all the elements in a given * double values bi-dimensional array. * </p> * @param x the bi-dimensional array of doubles to copy * @return a bi-dimensional array of double values as a copy of x. */ private double[][] clone(double[][] x) { double[][] res=new double[x.length][]; for (int i=0;i<x.length;i++) res[i]=clone(x[i]); return res; } /** * <p> * This private method copies all the elements in a given * double values bi-dimensional array but the last one in each row, * which is skipped. * The resultant matrix has one column less than the given one. * </p> * @param x the bi-dimensional array of doubles to truncate * @return a bi-dimensional array of double values truncating the last column in x. */ private double[][] truncateColumn(double[][] x) { double[][] res=new double[x.length-1][]; for (int i=0;i<res.length;i++) res[i]=truncate(x[i]); return res; } /** * <p> * This private method copies all the rows in a given double * values bi-dimensional array but the last row, which is skipped. * The resultant matrix has one row less than the given one. * </p> * @param x the bi-dimensional array of doubles to truncate * @return a bi-dimensional array of double values truncating the last row in x. */ private double[][] truncateRow(double[][] x) { double[][] res=new double[x.length-1][]; for (int i=0;i<res.length;i++) res[i]=clone(x[i]); return res; } /** * <p> * This private method inserts in a matrix one new row. * </p> * @param x the bi-dimensional array of doubles * @param y the array of doubles to insert as the last row * @return a bi-dimensional array of double values with the new row included. */ private double[] insertRow(double[] x, double y) { double[] res=new double[x.length+1]; for (int i=0;i<x.length;i++) res[i]=x[i]; res[res.length-1]=y; return res; } /** * <p> * This method groups two Clusters in a new one provided both are independent. * Otherwise an exception is thrown. * </p> * @param l the first (left) Cluster * @param r the second (right) cluster * @return a new Cluster. * @throws {@link MatrixCalcs.DimensionError}, {@link MatrixCalcs.SingularError} * if the Clusters given as parameters aren't independent. */ Cluster groupTwoClusters(Cluster l, Cluster r) throws MatrixCalcs.DimensionError, MatrixCalcs.SingularError { Cluster result = new Cluster(); double p=(1.0*l.n)/(l.n+r.n); result.n=l.n+r.n; result.m=MatrixCalcs.matSum(MatrixCalcs.matMul(l.m,p),MatrixCalcs.matMul(r.m,(1-p))); double[][] tmpl=MatrixCalcs.matMul(l.C,p); double[][] tmpr=MatrixCalcs.matMul(r.C,1-p); double[][] mresta=MatrixCalcs.matDif(l.m,r.m); double[][] tmpm=MatrixCalcs.matMul(mresta,MatrixCalcs.tr(mresta)); tmpm=MatrixCalcs.matMul(tmpm,p*(1-p)); result.C=MatrixCalcs.matSum(tmpl,MatrixCalcs.matSum(tmpr,tmpm)); result.e=Math.log(MatrixCalcs.determinant(result.C)); result.leftHandStree=l; result.rightHandStree=r; result.ord=-1; return result; } /** * <p> * This method sets a label to a the first unlabeled Cluster in the dendogram. * The depth-search is left-handed search. * </p> * @param c the list of labels, an array of integers * @param cl the dendogram, a Cluster * @param val the label, an integer */ void setLabel(int c[], Cluster cl, int val) { if (cl.ord>=0) { c[cl.ord]=val; } else { setLabel(c,cl.leftHandStree,val); setLabel(c,cl.rightHandStree,val); } } /** * <p> * Class constructor. * </p> * @param pX the input data from the dataset as a bi-dimensional double array * @param pY the output data from the dataset as an array of doubles */ public RSFSS(double[][]pX, double[]pY) { System.out.println("Generating an RSFSS"); X=pX; Y=pY; } //Modelling algorithm based on Random sets FSS 2000 /** * <p> * This methods carries out the modelling algorithm based on Random Sets FSS 2000 without using * lables for the clusters. * </p> * @param NC an integer with the number of clusters to generate * @param r a Randomize object * @param sigma a double value with the sigmoide value for the centres membership functions */ public void RSFSSX3(int NC, Randomize r, double sigma) { double [][]C0=MatrixCalcs.matMul(MatrixCalcs.I(X[0].length+1),sigma); Cluster dendogram[]=new Cluster[X.length]; boolean unmarked[]=new boolean[X.length]; try { int numclusters=X.length; for (int i=0;i<X.length;i++) { dendogram[i]=new Cluster(); dendogram[i].m=MatrixCalcs.oneColumnMatrix(insertRow(X[i],Y[i])); dendogram[i].C=clone(C0); dendogram[i].n=1; dendogram[i].e=Math.log(MatrixCalcs.determinant(dendogram[i].C)); dendogram[i].leftHandStree=null; dendogram[i].rightHandStree=null; dendogram[i].ord=i; } do { // Nearest cluster are joined double minEnergy=0; int mini=0; int minj=0; boolean isTheFirst=true; for (int i=0;i<X.length;i++) { if (unmarked[i]) continue; for (int j=i+1;j<X.length;j++) { if (unmarked[j]) continue; Cluster tmp=groupTwoClusters(dendogram[i],dendogram[j]); if (tmp.e<minEnergy || isTheFirst) { isTheFirst=false; minEnergy=tmp.e; mini=i; minj=j; } } } //System.out.println("Number of clusters="+numclusters+". Clusters association"+mini+" "+minj); dendogram[mini]=groupTwoClusters(dendogram[mini],dendogram[minj]); unmarked[minj]=true; dendogram[minj].n=0; numclusters--; } while(numclusters!=NC); // Let's calcule regression plane for each cluster points/examples A=new double[NC][][]; Covar=new double[NC][][]; int c[]=new int[X.length]; centres = new double[NC][][]; int num[]=new int[NC]; meanY = new double[NC]; w=new double[NC]; int theRule=0; for (int example=0;example<X.length;example++) { if (unmarked[example]) continue; System.out.println("Cluster labelling "+theRule); Covar[theRule]=MatrixCalcs.inv(truncateColumn(dendogram[example].C)); setLabel(c,dendogram[example],theRule); centres[theRule]=truncateRow(dendogram[example].m); meanY[theRule]=dendogram[example].m[dendogram[example].m.length-1][0]; num[theRule]=dendogram[example].n; w[theRule]=(1.0*num[theRule])/X.length*MatrixCalcs.determinant(Covar[theRule]); System.out.println("Cluster associated examples "+theRule+" = "+num[theRule]); theRule++; } // It's only used examples corresponding to each rule double theWeights[] = new double[c.length]; for (theRule=0; theRule<NC; theRule++) { System.out.println("Consequent processing "+theRule); // Regression planes are calculated // Xm is X - centros[theRule] * root weight // Ym is Y - Y mean * root weight double[][] Xm = new double[num[theRule]][X[0].length]; double[][] Ym = new double[num[theRule]][1]; int example=0; for (int i=0;i<X.length;i++) { if (c[i]!=theRule) continue; for (int j=0;j<Xm[example].length;j++) { Xm[example][j]=(X[i][j]-centres[theRule][j][0]); } Ym[example][0]=(Y[i]-meanY[c[i]]); example++; } A[theRule] = MatrixCalcs.matMul( MatrixCalcs.matMul( MatrixCalcs.inv(MatrixCalcs.matMul(MatrixCalcs.tr(Xm),Xm)), MatrixCalcs.tr(Xm)),Ym); System.out.print("Rule coefficient "+theRule+" "); for (int i=0;i<A[theRule].length;i++) System.out.print(A[theRule][i][0]+" "); System.out.print(" Y="+meanY[theRule]+" centres="); for (int i=0;i<centres[theRule].length;i++) System.out.print(centres[theRule][i][0]+" "); System.out.println(); } } catch(MatrixCalcs.SingularError e) { System.err.println("Singular Matrix: "+e); } catch(MatrixCalcs.DimensionError e) { System.err.println("Internal Error: "+e); } } /** * <p> * This methods returns a double value with the membership degree of an example to a given * cluster. * </p> * @param x the example for which its membership degreee is to be evaluated * @param c the centres matrix * @param C the covariance matrix * @return the double value with the membership degree of the given example. * @throws {@link MatrixCalcs.DimensionError} if any calculation error occurs */ double evaluateMembership(double x[], double c[][], double C[][]) throws MatrixCalcs.DimensionError { double [][] xc = MatrixCalcs.matDif(MatrixCalcs.oneRowMatrix(x),MatrixCalcs.tr(c)); double[][] tmp = MatrixCalcs.matMul(xc,C); tmp = MatrixCalcs.matMul(tmp,MatrixCalcs.tr(xc)); // This parameter can be line command parameter return Math.exp(-0.5*tmp[0][0]); } /** * <p> * This methods returns a double value with the distance between the given example and * a cluster. * </p> * @param x the example for which its membership degreee is to be evaluated * @param c the centres matrix * @param A the rule coefficient * @return the double value with the distance of the given example and the cluster. */ double predy(double []x, double [][]c, double[][]A, double my) { double suma=0; for (int i=0;i<x.length;i++) suma+=(x[i]-c[i][0])*A[i][0]; return my+suma; } /** * <p> * This methods returns a evaluation of the given example using all the clusters found. * </p> * @param x the example for which its membership degreee is to be evaluated * @return the double array with the evaluation of the given example for eac cluster. */ public double[] getOutput(double []x) { double num=0; double den=0; try { for (int i=0;i<Covar.length;i++) { double mu = evaluateMembership(x,centres[i],Covar[i]); double sal= predy(x,centres[i],A[i],meanY[i]); num+=w[i]*mu*sal; den+=w[i]*mu; } } catch (MatrixCalcs.DimensionError e) { System.err.println("Internal Error"); } double res[] = new double[1]; if (den>0) res[0]=num/den; return res; } //Modelling algorithm based on Random sets FSS 2000 /** * <p> * This methods carries out the modelling algorithm based on Random Sets FSS 2000 using * lables for the clusters. * </p> * @param NC an integer with the number of clusters to generate * @param r a Randomize object * @param sigma a double value with the sigmoide value for the centres membership functions */ public void RSFSSX2(int NC, Randomize r, double sigma) { double [][]C0=MatrixCalcs.matMul(MatrixCalcs.I(X[0].length),sigma); Cluster dendogram[]=new Cluster[X.length]; boolean unmarked[]=new boolean[X.length]; try { int numclusters=X.length; for (int i=0;i<X.length;i++) { dendogram[i]=new Cluster(); dendogram[i].m=clone(MatrixCalcs.oneColumnMatrix(X[i])); dendogram[i].C=clone(C0); dendogram[i].n=1; dendogram[i].e=Math.log(MatrixCalcs.determinant(dendogram[i].C)); dendogram[i].leftHandStree=null; dendogram[i].rightHandStree=null; dendogram[i].ord=i; } do { // Nearest cluster are joined double minEnergy=0; int mini=0; int minj=0; boolean theFirst=true; for (int i=0;i<X.length;i++) { if (unmarked[i]) continue; for (int j=i+1;j<X.length;j++) { if (unmarked[j]) continue; Cluster tmp=groupTwoClusters(dendogram[i],dendogram[j]); if (tmp.e<minEnergy || theFirst) { theFirst=false; minEnergy=tmp.e; mini=i; minj=j; } } } //System.out.println("Clusters="+numclusters+". Cluster association "+mini+" "+minj); dendogram[mini]=groupTwoClusters(dendogram[mini],dendogram[minj]); unmarked[minj]=true; dendogram[minj].n=0; numclusters--; } while(numclusters!=NC); // Let's calcule regression plane for each cluster points/examples A=new double[NC][][]; Covar=new double[NC][][]; int c[]=new int[X.length]; centres = new double[NC][][]; w = new double[NC]; int theRule=0; for (int example=0;example<X.length;example++) { if (unmarked[example]) continue; System.out.println("Cluster labelling "+theRule); Covar[theRule]=MatrixCalcs.inv(dendogram[example].C); setLabel(c,dendogram[example],theRule); centres[theRule]=clone(dendogram[example].m); theRule++; } // It's calculated means for independent variables int num[]=new int[NC]; meanY = new double[NC]; for (int example=0;example<X.length;example++) { meanY[c[example]]+=Y[example]; num[c[example]]++; } for (theRule=0;theRule<NC;theRule++) { System.out.println("Cluster association examples "+theRule+" = "+num[theRule]); meanY[theRule]/=num[theRule]; w[theRule]=(1.0*num[theRule])/X.length*MatrixCalcs.determinant(Covar[theRule]); } double theWeights[] = new double[c.length]; for (theRule=0; theRule<NC; theRule++) { System.out.println("Consequent processing "+theRule); // Regression planes are calculated // Xm is X - centros[theRule] * root weight // Ym is Y - Y mean * root weight double[][] Xm = new double[num[theRule]][X[0].length]; double[][] Ym = new double[num[theRule]][1]; int example=0; for (int i=0;i<X.length;i++) { if (c[i]!=theRule) continue; for (int j=0;j<Xm[example].length;j++) { Xm[example][j]=(X[i][j]-centres[theRule][j][0]); } Ym[example][0]=(Y[i]-meanY[c[i]]); example++; } try { A[theRule] = MatrixCalcs.matMul( MatrixCalcs.matMul( MatrixCalcs.inv(MatrixCalcs.matMul(MatrixCalcs.tr(Xm),Xm)), MatrixCalcs.tr(Xm)),Ym); } catch(MatrixCalcs.SingularError e) { System.err.println("Quite few examples for theRule "+ theRule+" : "+e+" : "); A[theRule]=new double[X[0].length][1]; } System.out.print("Rule Coefficients "+theRule+" "); for (int i=0;i<A[theRule].length;i++) System.out.print(A[theRule][i][0]+" "); System.out.print(" Y="+meanY[theRule]+" entres="); for (int i=0;i<centres[theRule].length;i++) System.out.print(centres[theRule][i][0]+" "); System.out.println(); } } catch(MatrixCalcs.SingularError e) { System.err.println("Internal Error:" +e); } catch(MatrixCalcs.DimensionError e) { System.err.println("Internal Error: "+e); } } }