Data Model Documentation

These HTML pages are available in book form as a postscript file and as a. PDF file.


Overview of the Data Model

The ABLE data model provides a common set of literal and variable data objects that are used in other ABLE components, such as filters, rulesets, and inference engines, and can be extended by others for private needs.

Literals are immutable objects and are assigned a value at construction time. Variables can be assigned values at any time, either from other variables or from literals. A set of operators allows comparing literals and variables and assigning new values to variables.

All literals and variables are typed, and fall into one of several categories:

  1. Boolean - values are either true or false.
  2. Byte - values are integer numbers, which are represented internally as Java bytes.
  3. Character - values are single-quoted characters or control values.
  4. Double - values are real numbers, which are represented internally as Java doubles.
  5. Float - values are real numbers, which are represented internally as Java floats.
  6. Integer - values are integer numbers, which are represented internally as Java ints.
  7. Long - values are integer numbers, which are represented internally as Java longs.
  8. Short - values are integer numbers, which are represented internally as Java shorts.
  9. String - values are Java Strings.
  10. Object - values are any Java Object.

When assigning or comparing values, some attempt is made at converting one data type to another. For example, a Double variable may be assigned a value from a Boolean variable (or literal) since a boolean data object, whose value is either true or false, is considered to have a numeric value of either 1.0 or 0.0, respectively. However, not all combinations of data assignment and comparison are possible, and AbleDataExceptions are thrown when appropriate. For example, the less than operator has no meaning for generic data types whose "real" Java data types are not numbers or strings at the time an assignment or comparison is made.

In adition to the data types mentioned above, there is another data type, called a call literal. Like other literals, it is a read-only object, but one that wraps an ABLE user-defined function or method call. This means that every time a call literal's current value is requested, the data that is returned is actually the data obtained by calling the wrappered function. The returned data can be any Java Object, but must be, of course, a type expected by the receiving application.

All literals and variables implement, at minimum, the following methods found in the AbleRd interface, which is the interface that must be implemented by all "readable" data objects:

  public boolean      getBooleanValue()
  public AbleFuzzySet getFuzzyValue()
  public Object       getGenericValue()
  public double       getNumericValue()
  public String       getStringValue()
  public AbleLiteral  getValue()
      

AbleLiteral is a partial implementation of the AbleRd interface; AbleBooleanLiteral, AbleCallLiteral, AbleFuzzySet, AbleGenericLiteral, AbleDoubleLiteral, and AbleStringLiteral are the concrete implementations.

Variables implement, at minimum, the additional following methods found in the AbleWr interface, which is the interface that must be implemented by all "writable" data objects:

  public void setBooleanValue(boolean)
  public void setFuzzyValue(AbleFuzzySet)
  public void setGenericValue(Object)
  public void setNumericValue(double)
  public void setStringValue(String)
  public void setValue(AbleLiteral)
      

AbleVariable is a partial implementation of the AbleWr interface; AbleBooleanVariable, AbleCategoricalVariable, AbleContinuousVariable, AbleDiscreteVariable, AbleFuzzyVariable, AbleGenericVariable, AbleDoubleVariable, and AbleStringVariable are the concrete implementations.

Given the "get" and "set" methods listed above, the following coding is possible:

  double  aDbl  = someNumericVar.getNumericValue();
  boolean aBool = someNumericVar.getBooleanValue();
  String  aStr  = someNumericVar.getStringValue();

  anotherNumericVar.setNumericValue(aDbl);
  anotherNumericVar.setNumericValue(someNumericVar.getNumericValue());
  anotherNumericVar.setStringValue(aStr);

  anotherNumericVar.setValue(someNumericVar.getValue());

  anyTypeOfVar.setValue(anyOtherVar.getValue());
  anyTypeOfVar.setValue(anyTypeOfLiteral);

  if (someNumericVar.getNumericValue() <= anotherNumericVar.getNumericValue())
      

However, all of the assignment and comparison operations above can be better accomplished using the built-in "operators" defined in the AbleRd and AbleWr classes. AbleRd, the interface that defines "readable" data objects, defines these comparison operators, which are implemented in all AbleLiterals and AbleVariables:

  public boolean cmpEq  (AbleRd) // ==
  public boolean cmpGt  (AbleRd) // >
  public boolean cmpGtEq(AbleRd) // >=
  public double  cmpIs  (AbleRd) // is, fuzzy compare
  public boolean cmpLt  (AbleRd) // <
  public boolean cmpLtEq(AbleRd) // <=
  public boolean cmpNeq (AbleRd) // !=
      

AbleWr, the interface that defines "writable" data objects, defines these assignment operators, which are implemented in all AbleVariables:

  public void asgnEq(AbleRd)         // boolean assignment
  public void asgnIs(AbleRd)         // fuzzy assignment
  public void asgnIs(AbleRd, double) // fuzzy asignment with correlation
      

Given the above comparison and assignment operators, the following style of coding is possible:

  if ( someNumericVar.cmpLtEq(anotherNumericVar) ) {
    someStringVar.asgnEq(anotherStringVar);
  }
      

...and so on. In summary, these are the comparison operators implemented by all AbleLiterals and AbleVariables:

Method Function Usage
cmpEq Boolean compare, equal to (==) AbleRd.cmpEq(AbleRd)
cmpGt Boolean compare, greater than (>) AbleRd.cmpGt(AbleRd)
cmpGtEq Boolean compare, greater than or equal to (>=) AbleRd.cmpGtEq(AbleRd)
cmpIs Fuzzy compare (is) AbleFuzzyVariable.cmpIs(AbleFuzzySet)
cmpLt Boolean compare, less than (<) AbleRd.cmpLt(AbleRd)
cmpLtEq Boolean compare, less than or equal to (<=) AbleRd.cmpLtEq(AbleRd)
cmpNeq Boolean compare, not equal to (!=) AbleRd.cmpNeq(AbleRd)

And these are the assignment operators implemented by all AbleVariables:

Method Function Usage
asgnEq Boolean assignment (=) AbleVariable.asgnEq(AbleRd)
asgnIs Fuzzy assignment (is) AbleFuzzyVariable.asgnEq(AbleFuzzySet)

The remainder of this paper contains further details about all literals and variables in the Able data package.


Class Hierarchy

Here are the classes that make up the Able Data Model:

Remember that all literals and variables are classifed into basic types:

  1. Boolean
  2. Byte
  3. Character
  4. Double
  5. Float
  6. Integer
  7. Long
  8. Short
  9. String
  10. Object
  11. and lastly,

  12. CallLiteral

Essentially, any data object can be compared to any other data object, and any data object and be assigned to any variable. This is accomplished through the various get...Value() and set...Value() methods. The following sections list the data objects in each category (boolean, double, string, and generic) and contain a chart showing what each get...Value() method returns. Each method's return value depends, of course, on the data object's actual current "raw" value at the time the method is invoked.

Looking at the chart for boolean data types, for example, you can see that when a boolean variable's current value is true, getBooleanValue() returns true, getNumericValue() returns 1.0, and getStringValue() returns "True", but when the current value is false getBooleanValue() returns false, getNumericValue() returns 0.0, and getStringValue() returns "False". Thus it is possible to assign a numeric variable a value from a boolean literal or variable, and so on.

When a particular combination is not possible, or when the current raw value of a particular data object doesn't lend itself to conversion to another data type, an AbleDataException is thrown. This may happen, for example, when trying to assign a numeric variable a value from a string literal or string variable. If the source string data object contains something like "123.456" or "-0.005", the assignment is possible, because the string can be parsed into a number. But if the string data object contains something like "Kilroy was here", an AbleDataException is thrown.


Boolean Data Objects

There are two boolean data objects. They are:

For convenience, there are two pre-defined, static AbleBooleanLiterals: AbleData.True and AbleData.False.

Return values from boolean data object
get...Value() methods
Boolean object's
current value
getBooleanValue() getGenericValue() getNumericValue() getStringValue() getValue()
true true new Boolean(true) 1.0 "True" new AbleBooleanLiteral(true)
false false new Boolean(false) 0.0 "False" new AbleBooleanLiteral(false)

Numeric Data Objects

The numeric data objects are:

Return values from numeric data object
get...Value() methods
Numeric object's
current value
getBooleanValue() getGenericValue() getNumericValue() getStringValue() getValue()
0.0 false new Double(0.0) 0.0 "0.0" new AbleNumericLiteral(0.0)
any non-zero number, n.m true new Double(n.m) n.m "n.m" new AbleNumericLiteral(n.m)

String Data Objects

The string data objects are:

Return values from string data object
get...Value() methods
String object's
current value
getBooleanValue() getGenericValue() getNumericValue() getStringValue() getValue()
"true" (case insensitive) true new String("true") AbleDataException "true" new AbleStringLiteral("true")
"false" (case insensitive) false new String("false") AbleDataException "false" new AbleStringLiteral("false")
string form of a parsable number, "n.m" AbleDataException new String("n.m") (Double.valueOf("n.m")).doubleValue() "n.m" new AbleStringLiteral("n.m")
any other string, "foo" AbleDataException new String("foo") AbleDataException "foo" new AbleStringLiteral("foo")
Behavior of string data object
set...Value() methods
Source object's
current value
setBooleanValue() setGenericValue() setNumericValue() setStringValue() setValue()
boolean true setStringValue("true") N/A
boolean false setStringValue("false") N/A
Boolean, b N/A setBooleanValue(b.booleanValue()) N/A
Number, n N/A setNumericValue(n.doubleValue()) N/A
String, s N/A setStringValue(s) N/A
AbleLiteral, a N/A setValue(a) N/A
Object, o N/A AbleDataException N/A
any double, n.m N/A setStringValue(Double.toString(n.m)) N/A
any String, "foo" N/A "foo"
For categorical variables, "foo" must be in the list of acceptable strings.
N/A
any AbleLiteral, a N/A calls set...Value(a.get...Value()) depending on type of literal

Generic Data Objects

The generic data objects are:

Return values from generic data object
get...Value() methods
Generic object's
current value
getBooleanValue() getGenericValue() getNumericValue() getStringValue() getValue()
Boolean, b b.booleanValue() b 1.0 if true;
0.0, if false
"True" if true;
"False" if false
new AbleGenericLiteral(b)
Number, n false if n.doubleValue()==0.0;
true otherwise
n n.doubleValue() Double.toString(n.doubleValue()) new AbleGenericLiteral(n)
String, s true if s.equalsIgnoreCase("true");
false if s.equalsIgnoreCase("false"); otherwise AbleDataException
s (Double.valueOf(s)).doubleValue() or
AbleDataException
s new AbleGenericLiteral(s)
AbleLiteral, a a.getBooleanValue() a a.getNumericValue() a.getStringValue() new AbleGenericLiteral(a)
any other Object, o AbleDataException o AbleDataException o.toString() new AbleGenericLiteral(o)

CallLiteral Data Objects

The call literal objects are:

A call literal is a wrapper for an Able user-defined function. This means that every time a call literal's current value is requested, the data that is returned is actually the data obtained by immediately and synchronously calling the wrappered function. Call literals more or less expect that the data returned by the wrappered function is a Boolean, Number, or String, but in reality, any Java Object is allowed. The returned data must be, of course, a type expected by the receiving application, which will most likely use the getGenericValue() method to obtain the call literal's value.

While call literals may appear on both the left-hand and right-hand side of comparison expressions, they may appear only on the right-hand side of assignment expressions; that is, like any literal, you cannot assign a value to it.

A get...Value() chart is not given here, because the code dealing with return values from user-defined functions is too complex to summarize neatly in a table.


Extending the Data Objects

While it is not possible to add completely new data types to the Able data model, it is possible to extend any of the existing data objects with additional or modified behavior. If you want to create a ComplexNumberVariable, for example, you might start by extending the AbleNumericVariable class, the AbleContinuousVariable class, or the AbleDiscreteVariable class, depending on whether you want your complex numbers completely unrestricted, limited within a certain range, or limited to one-of-n complex values, respectively. If you choose to extend AbleContinuousVariable so that you can limit your complex numbers to a range, you probably need to override the setDiscourseLo(), setDiscourseHi(), and withinUniversOfDiscourse() methods, among others, to get the desired behavior. You also need to override or perhaps even add new "operator" methods appropriate for your new ComplexNumber data object.

The AbleFuzzyVariable object is an example of a new variable derived from an existing class: it is derived from AbleContinuousVariable.


Last modified: Fri Feb 9 10:52:49 CST 2001