package infosapient.system;
/*
* Copyright (c) 2001, Workplace Performance Tools, All Rights Reserved.
*
* LICENSE TO USE THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THE COMMON PUBLIC LICENSE 0.5
* ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM CONSTITUTES
* RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
*/
import infosapient.system.Observer;
import java.util.Vector;
import java.util.Enumeration;
import java.rmi.server.ObjID;
import com.objectspace.jgl.Array;
import com.objectspace.jgl.BinaryPredicate;
import infosapient.system.ObservableImpl;
/**
*
* Class FzyAttribute represents the 'Universe of Discourse' for a fuzzy space.
* I.e. it represents the translation of contigous crisp values into symbolic values such
* as 'high', 'light', etc. for a given attribute. An attribute is any given property or quality
* for an entity.
* <p> Examples of an attribute would be
* <nl> <ul> Engine temperature, </ul>
* <ul> Profits or sales for a company, </ul>
* <ul> A person's blood pressure. </ul> </nl>
*
*
* @author Michael McConnell
* @version $Revision: 1.1.1.1 $
*
*
*
* Added two new attributes and getter/setters to the class, description and prompt. Shannon Roubal 12/15/1999 11:10 AM
* Added a new construct to include the description and prompt values. Shannon Roubal 12/15/1999 11:10 AM
*
*/
public class FzyAttribute extends infosapient.system.FzyClauseComponent implements infosapient.system.Observer, infosapient.util.XMLOutput, java.io.Serializable, Cloneable {
static final long serialVersionUID = -3267846087168239892L;
private boolean solutionSetCreated = false;
private Vector sets = null;
private double currDomainValue = Double.NaN;
private double initialValue = Double.NaN;
private String attributeName = null;
private String attributeDescription = null;
private String attributePrompt = null;
private FzyKnowledgebase theKB = null;
private infosapient.system.FzySolutionSet solutionSet = null;
/*
* start inner class definitions
*/
class MembershipGreaterThan implements com.objectspace.jgl.BinaryPredicate {
infosapient.system.ObservableImpl obser = null;
double currValue;
public MembershipGreaterThan(infosapient.system.ObservableImpl o, double currValue) {
this.obser = o;
this.currValue = currValue;
}
public boolean execute(Object obj1, Object obj2) {
if ((obj1 instanceof FzySet) && (obj2 instanceof FzySet)) {
FzySet fs1 = (FzySet) obj1;
FzySet fs2 = (FzySet) obj2;
try {
return (fs1.getDOM(currValue) > fs2.getDOM(currValue));
} catch (Exception e) {
e.printStackTrace();
setChanged();
obser.notifyObservers(new FSEvent(this, "Error", e));
}
}
return false;
}
}
/*
* end inner class defs
*/
public FzyAttribute(FzyKnowledgebase kb) throws IllegalArgumentException {
super();
if (kb == null) throw new IllegalArgumentException("No knowledgebase provided.");
theKB = kb;
addObserver(kb);
sets = new Vector();
}
public FzyAttribute(String attribName, FzyKnowledgebase kb)throws IllegalArgumentException {
this(kb);
if (attribName == null) throw new IllegalArgumentException("No name provided for this attribute.");
setName(attribName);
}
/**
* Create a new attribute with name, description, prompt, and knowledgebase.
* @param String - the proposed attribute name (MAY NOT be null).
* @param String - the description of this attribute.
* @param String - the prompt for the attribute.
* @param FzyKnowledgebase - the kb that this attribute will be added to (cannot be null).
*/
public FzyAttribute(String attribName, String attribDesc, String attribPrompt, FzyKnowledgebase kb) throws IllegalArgumentException {
this(attribName, kb);
if (attribDesc != null) {
setDescription(attribDesc);
}
if (attribPrompt != null) {
setPrompt(attribPrompt);
}
}
/**
* Add a unique FzySet to this FzyAttribute.
* @param FzySet the set to be added to the attribute.
* @return boolean true if the set was added.
*/
public boolean addSet(FzySet aSet)throws IllegalArgumentException {
if (aSet == null) throw new IllegalArgumentException("Set cannot be null");
if ((sets.isEmpty()) || (!(containsSet(aSet)))) {
sets.addElement(aSet);
setChanged();
return true;
}
return false;
}
/**
* Add a set at a specific index.
* @param FzySet the set to be added.
* @param int the index that the set is to be placed at.
* @return boolean true if the set was added.
*/
public boolean addSet(FzySet aSet, int index){
if (sets.isEmpty()) {
sets.addElement(aSet);
} else {
if (!(containsSet(aSet))) {
try {
sets.insertElementAt(aSet,index);
setChanged();
return true;
} catch (ArrayIndexOutOfBoundsException aiooe) {
setChanged();
notifyObservers(new FSEvent(this, "Error", aiooe));
}
}
}
return false;
}
/**
* Used by the rules engine to find out what the current
* solution is by asking the user.
* @see FzyTorquemada#solveGoal
* @see FzyEngineController#handleAskPrompt
*
*/
public void ask() {
setChanged();
notifyObservers(new FSEvent(this, "Attribute:askPrompt", this));
}
/**
* Provides a deep copy of this attribute, including a copy of its set collection,
* goal set or attribute, currentDomainValue and solutionSet.
* @return Object a copy of this attribute
*/
public Object clone() {
FzyAttribute fa = new FzyAttribute(this.getName(),getKB());
fa.currDomainValue = this.currDomainValue;
for (int inx = 0; inx < sets.size(); inx++) {
FzySet fs = (FzySet)((FzySet)this.sets.elementAt(inx)).clone();
fs.setAttribute(fa);
fa.addSet((FzySet)fs);
}
//fa.setDescription(this.getDescription());
return (Object) fa;
}
/**
* returns a boolean if this attribute contains the given FzySet.
* @param FzySet -- the set to be found within this FzyAttribute.
* @return boolean -- true if found.
*/
public boolean containsSet(FzySet aSet) throws IllegalArgumentException {
if (aSet == null) throw new IllegalArgumentException("Fuzzy Set cannot be null!");
for(int inx = 0; inx < sets.size(); inx++){
if(((FzySet)sets.elementAt(inx)).equals(aSet.getID())) return true;
}
return false;
}
/**
* returns a boolean if this attribute contains the given FzySet <b><code>name</code></b>.
* @param String name -- the set to be found within this FzyAttribute.
* @return boolean -- true if found.
*/
public boolean containsSetNamed(String aName) throws IllegalArgumentException {
if (aName == null)
throw new IllegalArgumentException("Name cannot be null");
for (int knx = 0; knx < sets.size(); knx++) {
FzySet set = (FzySet) sets.elementAt(knx);
String name = set.getName();
if (name.equals(aName))
return true;
}
return false;
}
/**
* Checks whether a given value is within this domain and returns an array of FzySets
*
* @param double the value to be compared
* @return FzySet[] of all sets that this value is contained.
*/
public com.objectspace.jgl.Array containsValue(double value){
Array setArray = new Array(0);
try {
FzySet currentSet;
for (int i = 0; i < sets.size(); i++) {
currentSet = (FzySet)sets.elementAt(i);
if (currentSet.doesContain(value)) {
setArray.add((FzySet)sets.elementAt(i));
}
}
if (setArray.size() > 1) {
BinaryPredicate bp = (BinaryPredicate)
new MembershipGreaterThan((ObservableImpl) this, value);
com.objectspace.jgl.algorithms.Sorting.sort(setArray, bp);
}
} catch (Exception e) {
e.printStackTrace();
setChanged();
notifyObservers(new FSEvent(this,"Error", e));
}
return setArray;
}
/**
* Return the current domain value of this attribute.
* @return double the current domain value of this fuzzy set.
*/
public double getCurrentDomainValue() {
return currDomainValue;
}
/**
* Get the description for this attribute.
* @return String this.description
*/
public String getDescription(){
return this.attributeDescription;
}
/**
* Returns the highest membership within the domain of all fuzzy sets within this
* attribute.
* @param double the value within this domain
* @returns double the highest membership within this domain.
*/
public double getDOMForCollection(double value) throws IllegalArgumentException {
if (Double.isNaN(value)) throw new IllegalArgumentException("value is Double.NaN!");
double max = -1.0d;
double tmax;
try {
Array cVector = containsValue(value);
if (cVector.size() > 0) {
for (Enumeration e = cVector.elements(); e.hasMoreElements();) {
FzySet aSet = (FzySet) e.nextElement();
tmax = aSet.getDOM(value);
if (tmax > max) max = tmax;
}
return max;
} else {
FzySet fsTemp = (FzySet) sets.firstElement();
if (fsTemp.getLowDomain() >= value){
return fsTemp.getDOM(value);
} else {
fsTemp = (FzySet) sets.lastElement();
return fsTemp.getDOM(value);
}
}
} catch (Exception e) {
setChanged();
notifyObservers(new FSEvent(this, "Error", e));
}
return 0.0;
}
/**
* Get this attribute's initial value.
* Creation date: (2/8/00 11:31:13 AM)
* @return double
*/
public double getInitialValue() {
return initialValue;
}
/**
* Return the Knowledgebase that this attribute belongs to.
* @return FzyKnowledgebase -- the owning knowledgebase.
*/
public FzyKnowledgebase getKB() {
return theKB;
}
/**
* Get the prompt for this attribute.
* @return String this.prompt
*/
public String getPrompt(){
return this.attributePrompt;
}
/**
* returns a FzySet given its name.
* @param String name -- the set to be found within this FzyAttribute.
* @return FzySet -- if found; else null.
*/
public FzySet getSetNamed(String aName)throws IllegalArgumentException {
if (aName == null) throw new IllegalArgumentException("Name cannot be null");
boolean found = false;
FzySet set = null;
for (int knx = 0; knx < sets.size(); knx++) {
set = (FzySet) sets.elementAt(knx);
String name = set.getName();
if (name.equals(aName)){
return set;
}
}
return null;
}
/**
* Return an array containing the set names in sequence.
* Creation date: (1/1/00 3:48:02 PM)
* @author: Michael McConnell
*
* @return java.lang.String[]
*/
public String[] getSetNames() {
int inx = 0;
String nameArray[] = new String[sets().size()];
Enumeration e = sets().elements();
while (e.hasMoreElements()) {
nameArray[inx++] = ((FzySet)e.nextElement()).getName();
}
return nameArray;
}
public double getSolution() {
return currDomainValue;
}
public double getSolutionDOM() {
return getDOMForCollection(currDomainValue);
}
/**
* Return the solution set for this attribute. Lazy instantiate if it does
* not exist. Set the name of the solution set to be the attrib name.
* @return FzySolutionSet.
*/
public infosapient.system.FzySolutionSet getSolutionSet() {
if (solutionSet == null)
solutionSet = new FzySolutionSet(this);
return solutionSet;
}
public boolean hasSolution() {
return !Double.isNaN(currDomainValue);
}
/**
* Used to represent this attribute with its sets when saving knowledgebase
* @param java.io.Writer - the outputWriter to use
* @param int - number of tabs to space over for this attribute.
*/
public void printOn(java.io.Writer outWriter, int nTabs) throws java.io.IOException {
StringBuffer tabs = new StringBuffer(nTabs+1);
for (int kt = 0; kt < nTabs+1; kt++) tabs.append("\t");
StringBuffer sb = new StringBuffer();
sb.append(tabs).append(this.getName()).append(" {\n");
outWriter.write(sb.toString());
for (int sinx = 0; sinx < sets.size(); sinx++)
((FzySet)sets.elementAt(sinx)).printOn(outWriter, nTabs+1);
sb = new StringBuffer();
sb.append(tabs).append("}\n");
outWriter.write(sb.toString());
}
/**
* Remove all sets within this Attribute. Typically only used just before deleting
* the attribute.
*/
public void removeAllSets() {
sets = null;
setChanged();
notifyObservers(new FSEvent(this, "Sets:null", null));
}
/**
* Remove a fuzzy set and return the index that the set was found at.
* This return value can be used to insert a new set at the same index.
* If -1, indicates that the set was not found within this attribute.
* @param FzySet The FzySet to be removed.
* @returns int The index of the set that was removed.
*/
public int removeFSet(FzySet rSet) throws IllegalArgumentException {
if (rSet == null) throw new IllegalArgumentException("Set cannot be null");
for (int knx = 0; knx < sets.size(); knx++){
if (rSet.equals((FzySet)sets.elementAt(knx))) {
sets.removeElementAt(knx);
setChanged();
return knx;
}
}
return -1;
}
/**
* Resets the current domain value to Double.NaN
*/
public void reset() {
setCurrentDomainValue(Double.NaN);
if (this.solutionSet != null) this.solutionSet.reset();
}
/**
* Required for FzyAttribute inner class support.
*/
public void setChanged(){
super.setChanged();
}
/**
* Set the current domain value of this attribute.
* @param double the current domain.
* @return FzyAttribute this attribute.
*/
public void setCurrentDomainValue(double value){
currDomainValue = value;
setChanged();
}
/**
* Set the description for this attribute.
* @param String the description
* @return FzyAttribute this attribute.
*/
public void setDescription(String aDesc){
attributeDescription = aDesc;
setChanged();
}
/**
* Set the initial value of this attribute.
* Creation date: (2/8/00 11:31:13 AM)
* @param newInitialValue double
*/
public void setInitialValue(double newInitialValue) {
initialValue = newInitialValue;
}
/**
* Set the prompt for this attribute.
* @param String the prompt
* @return FzyAttribute this attribute.
*/
public void setPrompt(String aPrompt){
attributePrompt = aPrompt;
setChanged();
}
/**
* Return the set collection as a java.util.Vector
* @return java.util.Vector sets -- the fuzzy set orderedCollection.
*/
public Vector sets(){
return sets;
}
public void setSolution(double d) {
currDomainValue = d;
}
/**
* String value of this object. Returns the Name of this FzyAttribute.
* @returns String -- the name of this attribute.
*/
public String toString() {
return getName();
}
/**
* Represent this attribute as xml tags.
* Creation date: (1/30/00 9:06:33 PM)
* @return java.lang.StringBuffer
*/
public StringBuffer toXML(int nTabs) {
StringBuffer xmlSB = new StringBuffer(10240);
for (int i = 0; i < nTabs; i++) xmlSB.append("\t");
xmlSB.append("<attribute id=\"" + getName() + "\"\n");
for (int i = 0; i < nTabs+1; i++) xmlSB.append("\t");
xmlSB.append("prompt=\"" + getPrompt() + "\"\n");
for (int i = 0; i < nTabs+1; i++) xmlSB.append("\t");
xmlSB.append("description=\"" + getDescription() + "\"\n");
if (this instanceof FzyBooleanAttribute) {
for (int i = 0; i < nTabs+2; i++) xmlSB.append("\t");
xmlSB.append("type=\"boolean\" \n");
}
for (int i = 0; i < nTabs; i++) xmlSB.append("\t");
xmlSB.append(">\n");
if (!(this instanceof FzyBooleanAttribute)) {
Vector tSV = sets();
Enumeration tSVenum = tSV.elements();
while (tSVenum.hasMoreElements()) {
FzySet s = (FzySet) tSVenum.nextElement();
xmlSB.append(s.toXML(nTabs+1));
}
}
for (int i = 0; i < nTabs; i++) xmlSB.append("\t");
xmlSB.append("</attribute>\n");
return xmlSB;
}
/**
* Used by the objects that I am observing to let me know that their
* state has changed.
*/
public void update(Observable obser, Object obj) {
setChanged();
if (!obser.equals(this))notifyObservers(obj);
}
}