package uk.ac.leeds.ccg.projects.MedAction.FuzzyInference; /* * FuzzyModel.java * * Created on June 27, 2002, 7:55 PM */ import java.util.Vector; import java.awt.*; import java.awt.image.*; import java.awt.geom.*; import java.io.*; /** * a fuzzy variable is defined for a input variable. it will contains a number of * fuzzy sets which is membership function. "Low", "High","Average". * @author jianhui jin */ public class FuzzyVariable implements Serializable { // the fuzzy set contained, or the membership functions contained AbstractFuzzySet[] set = null; //Vector setVector=null; // the fuzzy variable's name, usually use the input variable name String name = ""; // fuzzy set type, which is the class extending AbstractFuzzySet private Class fuzzySetType; // for some reason, i didn't put the followed two attribute in fuzzyPanel // from object orientated view, they should be in fuzzyPanel, // i have forgot the reason to put them here // selected fuzzy set in a fuzzy panel. AbstractFuzzySet selectedSet = null; // selected fuzzy point in a fuzzy point FuzzyPoint selectedPoint = null; /** Creates a new instance of FuzzyModel * with 4 default fuzzy sets. */ public FuzzyVariable( String name ) { this.name = name; iniFuzzyVariable( 4 ); } /** * read the parameters object ob from a serielised saved object array file * * @param ob fuzzy variable parameters, transfered using toObject() */ public FuzzyVariable( Object[] ob ){ this.setName( ( String ) ob[ 0 ] ); double[][][] value = ( double[][][] ) ob[ 1 ]; this.iniFuzzyVariable( value.length ); this.setFuzzySets( value ); } /** * * @param value */ public void setFuzzySets( double[][][] value ){ AbstractFuzzySet[] sets = this.getFuzzySet(); for( int i = 0; i < sets.length; i++ ) { sets[i].setFuzzyPoint( value[i] ); } } /** * * @param set fuzzy sets for a fuzzy varaible */ public void setFuzzySets( AbstractFuzzySet[] set ) { this.set = new AbstractFuzzySet[set.length]; for( int i = 0; i < set.length ; i++ ){ this.set[i] = set[i]; } } /** * * @param set set a fuzzy set in the variable's fuzzy set array * @param index */ public void setFuzzySet( AbstractFuzzySet set , int index ) { if( ( index < 0 ) || ( index >= this.set.length ) ) return; if( this.set[ index ].equals( this.getSelectedFuzzySet() ) ) { this.setSelectedSet( set ); } this.set[ index ] = set; } /** * * @param newSet * @param oldSet */ public void setFuzzySet( AbstractFuzzySet newSet , AbstractFuzzySet oldSet ) { AbstractFuzzySet[] sets = this.getFuzzySet(); AbstractFuzzySet selectedSet = this.getSelectedFuzzySet(); for( int i = 0; i < sets.length; i++ ) { if( sets[ i ].equals( selectedSet ) ) { sets[ i ] = newSet; break; } } this.setFuzzySets( sets ) ; if( oldSet.equals( selectedSet ) ) { this.setSelectedSet( newSet ); } } /** * this method will detect which fuzzy set in this variable is being clicked * or selected by mouse. it will calculate the distance between the clicking * point and all the points in the panel, the fuzzy set containing the closest * one is the one the mouse clicking selected. * * @param p mouse clicking point */ public void setSelectedFuzzySetByDetection( Point2D p ) { AbstractFuzzySet[] sets = this.getFuzzySet(); FuzzyPoint[] ps = sets[0].getFuzzyPoint(); double min = FuzzyPoint.distance( p, ps[0] ); int temp1 = 0, temp2 = 0; for( int i = 0; i < sets.length; i++ ) { ps = sets[i].getFuzzyPoint(); for( int j = 0; j < ps.length; j++) { if( FuzzyPoint.distance( p, ps[j] ) < min ) { min = FuzzyPoint.distance( p, ps[j] ); temp1 = i; temp2 = j; } } } this.selectedSet = sets[temp1]; this.setSelectedSetAndPointColor(); } /** * * @param p */ public void setSelectedFuzzySetAndPointByDetection( Point2D p ) { AbstractFuzzySet[] sets = this.getFuzzySet(); FuzzyPoint[] ps = sets[0].getFuzzyPoint(); double min = FuzzyPoint.distance( p, ps[0] ); int temp1 = 0, temp2 = 0; for( int i = 0; i < sets.length; i++ ) { ps = sets[i].getFuzzyPoint(); for( int j = 0; j < ps.length; j++) { if( FuzzyPoint.distance( p, ps[j] ) < min ) { min = FuzzyPoint.distance( p, ps[j] ); temp1 = i; temp2 = j; } } } sets[temp1].setColor( Color.PINK ); this.selectedSet = sets[temp1]; FuzzyPoint[] selected = sets[temp1].getFuzzyPoint(); this.selectedPoint = selected[temp2]; this.setSelectedSetAndPointColor(); } /** * * @return the selected FuzzySet */ public AbstractFuzzySet getSelectedFuzzySet(){ return this.selectedSet; } /** * calculate the distance between all points and the clicking point * the closing is the point the mouse clicking selected. * @param */ public void setSelectedFuzzyPointByDetection(Point2D p) { AbstractFuzzySet[] sets = this.getFuzzySet(); FuzzyPoint[] ps = sets[0].getFuzzyPoint(); double min = FuzzyPoint.distance( p, ps[0]); int temp1 = 0, temp2 = 0; for( int i = 0; i < sets.length; i++ ) { ps = sets[i].getFuzzyPoint(); for( int j = 0; j < ps.length; j++ ) { if( FuzzyPoint.distance( p, ps[j] ) < min ) { min = FuzzyPoint.distance( p, ps[j] ); temp1 = i; temp2 = j; } } } FuzzyPoint[] selected = sets[temp1].getFuzzyPoint(); this.selectedPoint = selected[temp2]; this.setSelectedSetAndPointColor(); } /** * the input is a fuzzy set, so calculate the distance between all its points * and the input point, the closest is the one you selected. * @param p * @param selectedSet */ public void setSelectedFuzzyPointByDetection(Point2D p, AbstractFuzzySet selectedSet) { FuzzyPoint[] ps = selectedSet.getFuzzyPoint(); double min = FuzzyPoint.distance( p, ps[0]); int temp = 0; for( int i = 0; i < ps.length; i++ ) { if( FuzzyPoint.distance( p, ps[ i ] ) < min ) { min = FuzzyPoint.distance( p, ps[ i ] ); temp = i; } } this.selectedPoint = ps[temp]; this.setSelectedSetAndPointColor(); } /** * * @return the selected point */ public FuzzyPoint getSelectedFuzzyPoint() { return this.selectedPoint; } // a private method to used in when selection event happen, call this // method to changed the color of selected point and fuzzy set private void setSelectedSetAndPointColor() { AbstractFuzzySet[] sets = this.getFuzzySet(); AbstractFuzzySet selectedSet = this.getSelectedFuzzySet(); FuzzyPoint selectedPoint = this.getSelectedFuzzyPoint(); for( int i = 0 ; i < sets.length; i++ ) { sets[i].setColor( Color.BLACK ); sets[i].setAllFuzzyPointColor( Color.BLACK ); } if( selectedSet == null ) { return; } this.selectedSet.setColor( Color.PINK ); if( selectedPoint == null ) { return; } this.selectedPoint.setColor( Color.GREEN ); } /** * add a fuzzy set to this variable, it simply reconstruct this variable, * but add one more set */ public void addSet(){ iniFuzzyVariable( set.length + 1 ); } /** * delete a fuzzy set, it simply reconstruct this variable, but just one set * less * */ public void deleteSet(){ iniFuzzyVariable( set.length - 1 ); } /** * every input will get a FuzzifictionResult Object for this variable as result * it takes a point in, but actually, it used only the point's X value. * then get the degrees for all the fuzzy sets in this variable. * */ public FuzzificationResult getFuzzificationResult( FuzzyPoint p ){ // get all the set AbstractFuzzySet[] sets = this.getFuzzySet(); Object[][] temp = new Object[ sets.length ][ 2 ]; // get the name and the degree of the fuzzy set for( int i = 0; i < sets.length; i++ ) { temp[ i ][ 0 ] = sets[ i ].getName(); temp[ i ][ 1 ] = new Double( sets[ i ].getDegree( p.x ) ); } // construct a fuzzification result return new FuzzificationResult( temp, getName() ); } /** * every input will get a FuzzifictionResult Object for this variable as result * it takes a point in, but actually, it used only the point's X value. * then get the degrees for all the fuzzy sets in this variable. * * * @param x the input value * @return a fuzzificationResult object which contain the degrees for all the member */ public FuzzificationResult getFuzzificationResult( double x ) { AbstractFuzzySet[] sets = this.getFuzzySet(); Object[][] temp = new Object[ sets.length ][ 2 ]; for( int i = 0; i < set.length; i++ ) { temp[ i ][ 0 ] = set[i].getName(); temp[ i ][ 1 ] = new Double( set[ i ].getDegree( x ) ); } return new FuzzificationResult( temp, getName() ); } /** * * @param p selected point */ public void setSelectedPoint( FuzzyPoint p ){ this.selectedPoint = p; } /** * * @param set selected set */ public void setSelectedSet( AbstractFuzzySet set ){ this.selectedSet = set; } /** * move the selected point to the new postion * @param newPosition the new positon for the selected point */ public void moveSet( FuzzyPoint newPosition ){ AbstractFuzzySet set = this.getSelectedFuzzySet(); FuzzyPoint p = this.getSelectedFuzzyPoint(); // only change the value inside the point object // so the variable will not loss reference p.setX(newPosition.getX()); p.setY(newPosition.getY()); set.check(); this.setFuzzySetName(); } /** * each set will have the same width except the first and last ones * the frist and last set will have half width of others. * for example, all set are triangular membership function, * then first and last will be 90 degree, triangular, others will be in the middle * and have the same width. */ private void iniFuzzyVariable( int setNumber ){ AbstractFuzzySet[] sets = this.getFuzzySet(); sets = new AbstractFuzzySet[ setNumber ]; // this width is only half width of the normal member width double width = 1.0 / ( setNumber - 1 ); for( int i = 0; i < setNumber; i++ ) { //sets[i] = new Triangular5PointFuzzySet( width * i, width ); sets[i] = new FuzzySet( 10, width * i, width ); } this.setFuzzySets(sets); setFuzzySetName(); } // assign fuzzy set name to all the fuzzy sets in terms of their top point's position based on X value // it will calculte how many sets in this variable first, // then the middle one will have "Average", or if the number of sets are even // then there will be "low average" and "high average" // the rest will be "very low" "low" "high" "very high", etc. "very very very low" // depends how many sets, it has. private void setFuzzySetName() { AbstractFuzzySet tempSet = null; AbstractFuzzySet[] sets = this.getFuzzySet(); double[] tempTopPointX = new double[sets.length]; // assign all the top point's x value to the temp double array for further process for( int i = 0; i < tempTopPointX.length; i++ ) { tempTopPointX[i] = sets[i].getTopPoint().getX(); } // if higher, then move up, finally, get the set array from low to high for assign name double temp = 0.0; for( int i = 0; i < tempTopPointX.length; i++ ) { for( int j = 0; j < tempTopPointX.length-i-1; j++ ) { if( tempTopPointX[j] >= tempTopPointX[j+1] ) { temp = tempTopPointX[j]; tempSet = sets[j]; tempTopPointX[j] = tempTopPointX[j + 1]; sets[j] = set[j+1]; sets[j+1]=tempSet; tempTopPointX[j+1]=temp; }// if higher, then move up; } } int veryLength=0; if( (tempTopPointX.length % 2) ==0 ) { veryLength=sets.length/2-1; sets[sets.length/2].setName("high average"); sets[sets.length/2-1].setName("low average"); } else { sets[sets.length/2].setName("average"); veryLength=sets.length/2; } for(int i = 0; i