/* * 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 2 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * FLR.java * Copyright (C) 2002 Ioannis N. Athanasiadis * */ package weka.classifiers.misc; import weka.classifiers.AbstractClassifier; import weka.core.*; import weka.core.Capabilities.Capability; import weka.core.TechnicalInformation.Field; import weka.core.TechnicalInformation.Type; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.Serializable; import java.util.Enumeration; import java.util.Vector; /** <!-- globalinfo-start --> * Fuzzy Lattice Reasoning Classifier (FLR) v5.0<br/> * <br/> * The Fuzzy Lattice Reasoning Classifier uses the notion of Fuzzy Lattices for creating a Reasoning Environment.<br/> * The current version can be used for classification using numeric predictors.<br/> * <br/> * For more information see:<br/> * <br/> * I. N. Athanasiadis, V. G. Kaburlasos, P. A. Mitkas, V. Petridis: Applying Machine Learning Techniques on Air Quality Data for Real-Time Decision Support. In: 1st Intl. NAISO Symposium on Information Technologies in Environmental Engineering (ITEE-2003), Gdansk, Poland, 2003.<br/> * <br/> * V. G. Kaburlasos, I. N. Athanasiadis, P. A. Mitkas, V. Petridis (2003). Fuzzy Lattice Reasoning (FLR) Classifier and its Application on Improved Estimation of Ambient Ozone Concentration. * <p/> <!-- globalinfo-end --> * <!-- technical-bibtex-start --> * BibTeX: * <pre> * @inproceedings{Athanasiadis2003, * address = {Gdansk, Poland}, * author = {I. N. Athanasiadis and V. G. Kaburlasos and P. A. Mitkas and V. Petridis}, * booktitle = {1st Intl. NAISO Symposium on Information Technologies in Environmental Engineering (ITEE-2003)}, * note = {Abstract in ICSC-NAISO Academic Press, Canada (ISBN:3906454339), pg.51}, * publisher = {ICSC-NAISO Academic Press}, * title = {Applying Machine Learning Techniques on Air Quality Data for Real-Time Decision Support}, * year = {2003} * } * * @unpublished{Kaburlasos2003, * author = {V. G. Kaburlasos and I. N. Athanasiadis and P. A. Mitkas and V. Petridis}, * title = {Fuzzy Lattice Reasoning (FLR) Classifier and its Application on Improved Estimation of Ambient Ozone Concentration}, * year = {2003} * } * </pre> * <p/> <!-- technical-bibtex-end --> * <!-- options-start --> * Valid options are: <p/> * * <pre> -R * Set vigilance parameter rhoa. * (a float in range [0,1])</pre> * * <pre> -B * Set boundaries File * Note: The boundaries file is a simple text file containing * a row with a Fuzzy Lattice defining the metric space. * For example, the boundaries file could contain the following * the metric space for the iris dataset: * [ 4.3 7.9 ] [ 2.0 4.4 ] [ 1.0 6.9 ] [ 0.1 2.5 ] in Class: -1 * This lattice just contains the min and max value in each * dimension. * In other kind of problems this may not be just a min-max * operation, but it could contain limits defined by the problem * itself. * Thus, this option should be set by the user. * If ommited, the metric space used contains the mins and maxs * of the training split.</pre> * * <pre> -Y * Show Rules</pre> * <!-- options-end --> * * For further information contact I.N.Athanasiadis (ionathan@iti.gr) * * @author Ioannis N. Athanasiadis (email: ionathan@iti.gr, alias: ionathan@ieee.org) * @version 5.0 * @version $Revision: 5928 $ */ public class FLR extends AbstractClassifier implements Serializable, Summarizable, AdditionalMeasureProducer, TechnicalInformationHandler { /** for serialization */ static final long serialVersionUID = 3337906540579569626L; public static final float EPSILON = 0.000001f; /** the RuleSet: a vector keeping the learned Fuzzy Lattices */ private Vector learnedCode; /** a double keeping the vignilance parameter rhoa */ private double m_Rhoa = 0.5; /** a Fuzzy Lattice keeping the metric space */ private FuzzyLattice bounds; /** a File pointing to the boundaries file (bounds.txt) */ private File m_BoundsFile = new File(""); /** a flag indicating whether the RuleSet will be displayed */ private boolean m_showRules = true; /** an index of the RuleSet (keeps how many rules are needed for each class) */ private int index[]; /** an array of the names of the classes */ private String classNames[]; /** * Returns default capabilities of the classifier. * * @return the capabilities of this classifier */ public Capabilities getCapabilities() { Capabilities result = super.getCapabilities(); result.disableAll(); // attributes result.enable(Capability.NUMERIC_ATTRIBUTES); result.enable(Capability.DATE_ATTRIBUTES); result.enable(Capability.MISSING_VALUES); // class result.enable(Capability.NOMINAL_CLASS); result.enable(Capability.MISSING_CLASS_VALUES); return result; } /** * Builds the FLR Classifier * * @param data the training dataset (Instances) * @throws Exception if the training dataset is not supported or is erroneous */ public void buildClassifier(Instances data) throws Exception { // can classifier handle the data? getCapabilities().testWithFail(data); // remove instances with missing class data = new Instances(data); data.deleteWithMissingClass(); // Exceptions statements for (int i = 0; i < data.numAttributes(); i++) { if (i != data.classIndex()) { AttributeStats stats = data.attributeStats(i); if(data.numInstances()==stats.missingCount || Double.isNaN(stats.numericStats.min) || Double.isInfinite(stats.numericStats.min)) throw new Exception("All values are missing!" + data.attribute(i).toString()); } //fi } //for if (!m_BoundsFile.canRead()) { setBounds(data); } else try { BufferedReader in = new BufferedReader(new FileReader(m_BoundsFile)); String line = in.readLine(); bounds = new FuzzyLattice(line); } catch (Exception e) { throw new Exception("Boundaries File structure error"); } if (bounds.length() != data.numAttributes() - 1) { throw new Exception("Incompatible bounds file!"); } checkBounds(); // Variable Declerations and Initialization index = new int[data.numClasses()]; classNames = new String[data.numClasses()]; for (int i = 0; i < data.numClasses(); i++) { index[i] = 0; classNames[i] = "missing Class Name"; } double rhoa = m_Rhoa; learnedCode = new Vector(); int searching; FuzzyLattice inputBuffer; // Build Classifier (Training phase) if (data.firstInstance().classIsMissing()) throw new Exception("In first instance, class is missing!"); // set the first instance to be the first Rule in the model FuzzyLattice Code = new FuzzyLattice(data.firstInstance(), bounds); learnedCode.addElement(Code); index[Code.getCateg()]++; classNames[Code.getCateg()] = data.firstInstance().stringValue(data. firstInstance().classIndex()); // training iteration for (int i = 1; i < data.numInstances(); i++) { //for all instances Instance inst = data.instance(i); int flag =0; for(int w=0;w<inst.numAttributes()-1;w++){ if(w!=inst.classIndex() && inst.isMissing(w)) flag=flag+1; } if (!inst.classIsMissing()&&flag!=inst.numAttributes()-1) { inputBuffer = new FuzzyLattice( (Instance) data.instance(i), bounds); double[] sigma = new double[ (learnedCode.size())]; for (int j = 0; j < learnedCode.size(); j++) { FuzzyLattice num = (FuzzyLattice) learnedCode.get(j); FuzzyLattice den = inputBuffer.join(num); double numden = num.valuation(bounds) / den.valuation(bounds); sigma[j] = numden; } //for int j do { int winner = 0; double winnerf = sigma[0]; for (int j = 1; j < learnedCode.size(); j++) { if (winnerf < sigma[j]) { winner = j; winnerf = sigma[j]; } //if } //for FuzzyLattice num = inputBuffer; FuzzyLattice winnerBox = (FuzzyLattice) learnedCode.get(winner); FuzzyLattice den = winnerBox.join(num); double numden = num.valuation(bounds) / den.valuation(bounds); if ( (inputBuffer.getCateg() == winnerBox.getCateg()) && (rhoa < (numden))) { learnedCode.setElementAt(winnerBox.join(inputBuffer), winner); searching = 0; } else { sigma[winner] = 0; rhoa += EPSILON; searching = 0; for (int j = 0; j < learnedCode.size(); j++) { if (sigma[j] != 0.0) { searching = 1; } //fi } //for if (searching == 0) { learnedCode.addElement(inputBuffer); index[inputBuffer.getCateg()]++; classNames[inputBuffer.getCateg()] = data.instance(i).stringValue( data.instance(i).classIndex()); } //fi } //else } while (searching == 1); } //if Class is missing } //for all instances } //buildClassifier /** * Classifies a given instance using the FLR Classifier model * * @param instance the instance to be classified * @return the class index into which the instance is classfied */ public double classifyInstance(Instance instance) { FuzzyLattice num, den, inputBuffer; inputBuffer = new FuzzyLattice(instance, bounds); // transform instance to fuzzy lattice // calculate excitations and winner double[] sigma = new double[ (learnedCode.size())]; for (int j = 0; j < learnedCode.size(); j++) { num = (FuzzyLattice) learnedCode.get(j); den = inputBuffer.join(num); sigma[j] = (num.valuation(bounds) / den.valuation(bounds)); } //for j //find the winner Code (hyperbox) int winner = 0; double winnerf = sigma[0]; for (int j = 1; j < learnedCode.size(); j++) { if (winnerf < sigma[j]) { winner = j; winnerf = sigma[j]; } //fi } //for j FuzzyLattice currentBox = (FuzzyLattice) learnedCode.get(winner); return (double) currentBox.getCateg(); } //classifyInstance /** * Returns a description of the classifier. * * @return String describing the FLR model */ public String toString() { if (learnedCode != null) { String output = ""; output = "FLR classifier\n=======================\n Rhoa = " + m_Rhoa; if (m_showRules) { output = output + "\n Extracted Rules (Fuzzy Lattices):\n\n"; output = output + showRules(); output = output + "\n\n Metric Space:\n" + bounds.toString(); } output = output + "\n Total Number of Rules: " + learnedCode.size() + "\n"; for (int i = 0; i < index.length; i++) { output = output + " Rules pointing in Class " + classNames[i] + " :" + index[i] + "\n"; } return output; } else { String output = "FLR classifier\n=======================\n Rhoa = " + m_Rhoa; output = output + "No model built"; return output; } } //toString /** * Returns a superconcise version of the model * * @return String descibing the FLR model very shortly */ public String toSummaryString() { String output = ""; if (learnedCode == null) { output += "No model built"; } else { output = output + "Total Number of Rules: " + learnedCode.size(); } return output; } //toSummaryString /** * Returns the induced set of Fuzzy Lattice Rules * * @return String containing the ruleset * */ public String showRules() { String output = ""; for (int i = 0; i < learnedCode.size(); i++) { FuzzyLattice Code = (FuzzyLattice) learnedCode.get(i); output = output + "Rule: " + i + " " + Code.toString(); } return output; } //showRules /** * Returns an enumeration describing the available options. <p/> * <!-- options-start --> * Valid options are: <p/> * * <pre> -R * Set vigilance parameter rhoa. * (a float in range [0,1])</pre> * * <pre> -B * Set boundaries File * Note: The boundaries file is a simple text file containing * a row with a Fuzzy Lattice defining the metric space. * For example, the boundaries file could contain the following * the metric space for the iris dataset: * [ 4.3 7.9 ] [ 2.0 4.4 ] [ 1.0 6.9 ] [ 0.1 2.5 ] in Class: -1 * This lattice just contains the min and max value in each * dimension. * In other kind of problems this may not be just a min-max * operation, but it could contain limits defined by the problem * itself. * Thus, this option should be set by the user. * If ommited, the metric space used contains the mins and maxs * of the training split.</pre> * * <pre> -Y * Show Rules</pre> * <!-- options-end --> * * @return enumeration an enumeration of valid options */ public Enumeration listOptions() { Vector newVector = new Vector(3); newVector.addElement(new Option( "\tSet vigilance parameter rhoa.\n" + "\t(a float in range [0,1])", "R", 1, "-R")); newVector.addElement(new Option( "\tSet boundaries File\n" + "\tNote: The boundaries file is a simple text file containing \n" + "\ta row with a Fuzzy Lattice defining the metric space.\n" + "\tFor example, the boundaries file could contain the following \n" + "\tthe metric space for the iris dataset:\n" + "\t[ 4.3 7.9 ] [ 2.0 4.4 ] [ 1.0 6.9 ] [ 0.1 2.5 ] in Class: -1\n" + "\tThis lattice just contains the min and max value in each \n" + "\tdimension.\n" + "\tIn other kind of problems this may not be just a min-max \n" + "\toperation, but it could contain limits defined by the problem \n" + "\titself.\n" + "\tThus, this option should be set by the user.\n" + "\tIf ommited, the metric space used contains the mins and maxs \n" + "\tof the training split.", "B", 1, "-B")); newVector.addElement(new Option( "\tShow Rules", "Y", 0, "-Y")); return newVector.elements(); } //listOptions /** * Parses a given list of options. <p/> * <!-- options-start --> * Valid options are: <p/> * * <pre> -R * Set vigilance parameter rhoa. * (a float in range [0,1])</pre> * * <pre> -B * Set boundaries File * Note: The boundaries file is a simple text file containing * a row with a Fuzzy Lattice defining the metric space. * For example, the boundaries file could contain the following * the metric space for the iris dataset: * [ 4.3 7.9 ] [ 2.0 4.4 ] [ 1.0 6.9 ] [ 0.1 2.5 ] in Class: -1 * This lattice just contains the min and max value in each * dimension. * In other kind of problems this may not be just a min-max * operation, but it could contain limits defined by the problem * itself. * Thus, this option should be set by the user. * If ommited, the metric space used contains the mins and maxs * of the training split.</pre> * * <pre> -Y * Show Rules</pre> * <!-- options-end --> * * @param options the list of options as an array of strings * @throws Exception if an option is not supported ( */ public void setOptions(String[] options) throws Exception { // Option -Y m_showRules = Utils.getFlag('Y', options); // Option -R String rhoaString = Utils.getOption('R', options); if (rhoaString.length() != 0) { m_Rhoa = Double.parseDouble(rhoaString); if (m_Rhoa < 0 || m_Rhoa > 1) { throw new Exception( "Vigilance parameter (rhoa) should be a real number in range [0,1]"); } } else m_Rhoa = 0.5; // Option -B String boundsString = Utils.getOption('B', options); if (boundsString.length() != 0) { m_BoundsFile = new File(boundsString); } //fi Utils.checkForRemainingOptions(options); } //setOptions /** * Gets the current settings of the Classifier. * * @return an array of strings suitable for passing to setOptions */ public String[] getOptions() { String[] options = new String[5]; int current = 0; options[current++] = "-R"; options[current++] = "" + getRhoa(); if (m_showRules) { options[current++] = "-Y"; } if (m_BoundsFile.toString() != "") { options[current++] = "-B"; options[current++] = "" + getBoundsFile(); } while (current < options.length) { options[current++] = ""; } return options; } // getOptions /** * Get rhoa * @return the value of this parameter */ public double getRhoa() { return m_Rhoa; } /** * Get boundaries File * @return the value of this parameter */ public String getBoundsFile() { return m_BoundsFile.toString(); } /** * Get ShowRules parameter * @return the value of this parameter */ public boolean getShowRules() { return m_showRules; } /** * Set rhoa * @param newRhoa sets the rhoa value * @throws Exception if rhoa is not in range [0,1] */ public void setRhoa(double newRhoa) throws Exception { if (newRhoa < 0 || newRhoa > 1) { throw new Exception( "Vigilance parameter (rhoa) should be a real number in range [0,1]!!!"); } m_Rhoa = newRhoa; } /** * Set Boundaries File * @param newBoundsFile a new file containing the boundaries */ public void setBoundsFile(String newBoundsFile) { m_BoundsFile = new File(newBoundsFile); } /** * Set ShowRules flag * @param flag the new value of this parameter */ public void setShowRules(boolean flag) { m_showRules = flag; } /** * Sets the metric space from the training set using the min-max stats, in case -B option is not used. * @param data is the training set */ public void setBounds(Instances data) { // Initialize minmax stats bounds = new FuzzyLattice(data.numAttributes() - 1); int k = 0; for (int i = 0; i < data.numAttributes(); i++) { if (i != data.classIndex()) { AttributeStats stats = data.attributeStats(i); bounds.setMin(k, stats.numericStats.min); bounds.setMax(k, stats.numericStats.max); k = k + 1; } //if } //for } //setBounds /** * Checks the metric space */ public void checkBounds() { for (int i = 0; i < bounds.length(); i++) { if (bounds.getMin(i) == bounds.getMax(i)) bounds.setMax(i, bounds.getMax(i) + EPSILON); } } /** * Returns the tip text for this property * @return tip text for this property suitable for * displaying in the explorer/experimenter gui */ public String rhoaTipText() { return " The vigilance parameter value" + " (default = 0.75)"; } /** * Returns the tip text for this property * @return tip text for this property suitable for * displaying in the explorer/experimenter gui */ public String boundsFileTipText() { return " Point the filename containing the metric space"; } /** * Returns the tip text for this property * @return tip text for this property suitable for * displaying in the explorer/experimenter gui */ public String showRulesTipText() { return " If true, displays the ruleset."; } /** * Returns the value of the named measure * @param additionalMeasureName the name of the measure to query for its value * @return the value of the named measure * @throws IllegalArgumentException if the named measure is not supported */ public double getMeasure(String additionalMeasureName) { if (additionalMeasureName.compareToIgnoreCase("measureNumRules") == 0) { return measureNumRules(); } else { throw new IllegalArgumentException(additionalMeasureName + " not supported (FLR)"); } } /** * Returns an enumeration of the additional measure names * @return an enumeration of the measure names */ public Enumeration enumerateMeasures() { Vector newVector = new Vector(1); newVector.addElement("measureNumRules"); return newVector.elements(); } /** * Additional measure Number of Rules * @return the number of rules induced */ public double measureNumRules() { if (learnedCode == null) return 0.0; else return (double) learnedCode.size(); } /** * Returns a description of the classifier suitable for * displaying in the explorer/experimenter gui * @return the description */ public String globalInfo() { return "Fuzzy Lattice Reasoning Classifier (FLR) v5.0\n\n" + "The Fuzzy Lattice Reasoning Classifier uses the notion of Fuzzy " + "Lattices for creating a Reasoning Environment.\n" + "The current version can be used for classification using numeric predictors.\n\n" + "For more information see:\n\n" + getTechnicalInformation().toString(); } /** * Returns an instance of a TechnicalInformation object, containing * detailed information about the technical background of this class, * e.g., paper reference or book this class is based on. * * @return the technical information about this class */ public TechnicalInformation getTechnicalInformation() { TechnicalInformation result; TechnicalInformation additional; result = new TechnicalInformation(Type.INPROCEEDINGS); result.setValue(Field.AUTHOR, "I. N. Athanasiadis and V. G. Kaburlasos and P. A. Mitkas and V. Petridis"); result.setValue(Field.TITLE, "Applying Machine Learning Techniques on Air Quality Data for Real-Time Decision Support"); result.setValue(Field.BOOKTITLE, "1st Intl. NAISO Symposium on Information Technologies in Environmental Engineering (ITEE-2003)"); result.setValue(Field.YEAR, "2003"); result.setValue(Field.ADDRESS, "Gdansk, Poland"); result.setValue(Field.PUBLISHER, "ICSC-NAISO Academic Press"); result.setValue(Field.NOTE, "Abstract in ICSC-NAISO Academic Press, Canada (ISBN:3906454339), pg.51"); additional = result.add(Type.UNPUBLISHED); additional.setValue(Field.AUTHOR, "V. G. Kaburlasos and I. N. Athanasiadis and P. A. Mitkas and V. Petridis"); additional.setValue(Field.TITLE, "Fuzzy Lattice Reasoning (FLR) Classifier and its Application on Improved Estimation of Ambient Ozone Concentration"); additional.setValue(Field.YEAR, "2003"); return result; } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 5928 $"); } /** * Main method for testing this class. * * @param args should contain command line arguments for evaluation * (see Evaluation). */ public static void main(String[] args) { runClassifier(new FLR(), args); } /** * <p>Fuzzy Lattice implementation in WEKA </p> * * @author Ioannis N. Athanasiadis * email: ionathan@iti.gr * alias: ionathan@ieee.org * @version 5.0 */ private class FuzzyLattice implements Serializable, RevisionHandler { /** for serialization */ static final long serialVersionUID = -3568003680327062404L; private double min[]; private double max[]; private int categ; private String className; //Constructors /** * Constructs a Fuzzy Lattice from a instance * @param dR the instance * @param bounds the boundaries file */ public FuzzyLattice(Instance dR, FuzzyLattice bounds) { min = new double[dR.numAttributes() - 1]; max = new double[dR.numAttributes() - 1]; int k = 0; for (int i = 0; i < dR.numAttributes(); i++) { if (i != dR.classIndex()) { if (!dR.isMissing(i)) { min[k] = (dR.value(i) > bounds.getMin(k)) ? dR.value(i) : bounds.getMin(k); max[k] = (dR.value(i) < bounds.getMax(k)) ? dR.value(i) : bounds.getMax(k); k = k + 1; } //if(!dR.isMissing(i)) else { min[k] = bounds.getMax(k); max[k] = bounds.getMin(k); k = k + 1; } //else } //if(i!=dR.classIndex()) } //for (int i=0; i<dR.numAttributes();i++) categ = (int) dR.value(dR.classIndex()); className = dR.stringValue(dR.classIndex()); } //FuzzyLattice /** * Constructs an empty Fuzzy Lattice of a specific dimension pointing * in Class "Metric Space" (-1) * @param length the dimention of the Lattice */ public FuzzyLattice(int length) { min = new double[length]; max = new double[length]; for (int i = 0; i < length; i++) { min[i] = 0; max[i] = 0; } categ = -1; className = "Metric Space"; } /** * Converts a String to a Fuzzy Lattice pointing in Class "Metric Space" (-1) * Note that the input String should be compatible with the toString() method. * @param rule the input String. */ public FuzzyLattice(String rule) { int size = 0; for (int i = 0; i < rule.length(); i++) { String s = rule.substring(i, i + 1); if (s.equalsIgnoreCase("[")) { size++; } } min = new double[size]; max = new double[size]; int i = 0; int k = 0; String temp = ""; int s = 0; do { String character = rule.substring(s, s + 1); temp = temp + character; if (character.equalsIgnoreCase(" ")) { if (!temp.equalsIgnoreCase(" ")) { k = k + 1; if (k % 4 == 2) { min[i] = Double.parseDouble(temp); } //if else if (k % 4 == 3) { max[i] = Double.parseDouble(temp); i = i + 1; } //else } // if (!temp.equalsIgnoreCase(" ") ){ temp = ""; } //if (character.equalsIgnoreCase(seperator)){ s = s + 1; } while (i < size); categ = -1; className = "Metric Space"; } // Functions /** * Calculates the valuation function of the FuzzyLattice * @param bounds corresponding boundaries * @return the value of the valuation function */ public double valuation(FuzzyLattice bounds) { double resp = 0.0; for (int i = 0; i < min.length; i++) { resp += 1 - (min[i] - bounds.getMin(i)) / (bounds.getMax(i) - bounds.getMin(i)); resp += (max[i] - bounds.getMin(i)) / (bounds.getMax(i) - bounds.getMin(i)); } return resp; } /** * Calcualtes the length of the FuzzyLattice * @return the length */ public int length() { return min.length; } /** * Implements the Join Function * @param lattice the second fuzzy lattice * @return the joint lattice */ public FuzzyLattice join(FuzzyLattice lattice) { // Lattice Join FuzzyLattice b = new FuzzyLattice(lattice.length()); int i; for (i = 0; i < lattice.min.length; i++) { b.min[i] = (lattice.min[i] < min[i]) ? lattice.min[i] : min[i]; b.max[i] = (lattice.max[i] > max[i]) ? lattice.max[i] : max[i]; } b.categ = categ; b.className = className; return b; } // Get-Set Functions public int getCateg() { return categ; } public void setCateg(int i) { categ = i; } public String getClassName() { return className; } public void setClassName(String s) { className = s; } public double getMin(int i) { return min[i]; } public double getMax(int i) { return max[i]; } public void setMin(int i, double val) { min[i] = val; } public void setMax(int i, double val) { max[i] = val; } /** * Returns a description of the Fuzzy Lattice * @return the Fuzzy Lattice and the corresponding Class */ public String toString() { String rule = ""; for (int i = 0; i < min.length; i++) { rule = rule + "[ " + min[i] + " " + max[i] + " ] "; } rule = rule + "in Class: " + className + " \n"; return rule; } /** * Returns the revision string. * * @return the revision */ public String getRevision() { return RevisionUtils.extract("$Revision: 5928 $"); } } }