ARL Master Index

# Miscellaneous

This section covers some miscellaneous topics dealing with ABLE rulesets.

On this page...

- Built-in Variables

- Functions - Interacting with the World Outside of the RuleSet
  - Built-in Functions
  - Function Libraries
  - Externally Attached Functions

- Debugging a RuleSet

- Working with a RuleSet Programmatically

- Tips for Writing Rules

### Built-in Variables

Able provides the following built-in variables, all of which may be referenced in rules. These variables are, for the most part, read-only variables. You must not attempt to redefine them in the variables section of a ruleset.

this
  A reference to the ruleset itself.

parent
  A reference to the object, if any, that contains the ruleset.

functionList
  The list of imported functions.

variableList
  A list of global variables declared in the ruleset.

inputBuffer
  A reference to the ruleset's external input buffer. It is an Object array.

outputBuffer
  A reference to the ruleset's external output buffer. It is an Object array.

wm
  A reference to the ruleset's working memory.

null
  The value null.

Return to top

### Functions - Interacting with the World Outside of the RuleSet

Functions allow rules to interact with the outside world. For example, a rule can invoke a function to read a gauge, such as a thermometer, and use the returned value to set a variable. Or, a function can be used notify some other program about some action it should take, causing some side-effect. Or a function might be used to send an e-mail. The uses of functions are many and varied.

There are several ways to make functions available to rules. First of all, there are built-in functions provided by all rulesets. These are described in Built-In Functions below. Another way is to import Java classes into a ruleset so that all the public methods in the imported classes become accessible to your rules. This technique is described below in Function Libraries. And yet another way is to use Externally Attached Functions, also described below.

#### Built-in Functions

Able provides a set of built-in functions that are always available in all rulesets. The built-in functions listed below may be referenced in any rule without any additional work on the part of the rule writer.

Note that built-in functions always take precedence over imported function library functions of the same name and arity, but that externally attached functions can override built-in and imported functions.

invokeRuleBlock(string)
  Invokes the specified rule block, which must be declared in the current ruleset.

getRuleSetName()
  Returns a string that is the ruleset's name.

getVariable(string)
  Returns a reference to the specified variable.

getNumInputVars()
  Returns the number of variables listed in the InputVariables statement.

getNumOutputVars()
  Returns the number of variables listed in the OutputVariables statement.

getOutputVars()
  Returns a list of the variables listed in the OutputVariables statement.

setBaseTraceLevelNone()
setBaseTraceLevelLow()
setBaseTraceLevelMedium()
setBaseTraceLevelHigh()
  Turns base ruleset tracing to off, low, medium, or high.

getBaseTraceLevel()
  Returns the current base ruleset tracing level.

isBaseTraceActive()
  Returns a boolean that indicates whether base ruleset tracing is on or off.

setInferenceTraceLevelNone()
setInferenceTraceLevelLow()
setInferenceTraceLevelMedium()
setInferenceTraceLevelHigh()
  Turns inference engine tracing to off, low, medium, or high.

getInferenceTraceLevel()
  Returns the current inference engine tracing level.

isInferenceTraceActive()
  Returns a boolean that indicates whether inference engine tracing is on or off.

logInferenceTrace(string)
  Writes a message to the trace log.

logInferenceMessage(string)
  Writes a message to the message log.

setParseTraceLevelNone()
setParseTraceLevelLow()
setParseTraceLevelMedium()
setParseTraceLevelHigh()
  Turns parser tracing to off, low, medium, or high.

getParseTraceLevel()
  Returns the current parser tracing level.

isParseTraceActive()
  Returns a boolean that indicates whether parser tracing is on or off.

getCurrentDateAndTime()
  Returns a Calendar instance obtained from Calendar.getInstance() that can be assigned to Object variables or user-defined variables.

getCurrentDateAndTime(String theTimeZoneId, String theLanguage, String theCountry)
  Returns a Calendar instance obtained from Calendar.getInstance() that can be assigned to Object variables or user-defined variables.

#### Function Libraries

The entire set of public methods in any arbitrary Java class can be made available to a ruleset all at once by simply "importing" the class into the ruleset. The Java class in a sense becomes a function library of the ruleset, and means that you can write your own specialized libraries of functions to meet your unique needs. The only restriction on Java classes you import is that, if you intend to serialize your Able ruleset, any imported classes must also be serializable. See the Import statement for details.

Note that if an imported function has the same name and arity as a built-in function, the built-in function takes precedence. Note also that externally attached functions can override both built-in and imported functions.

Able provides you with these built-in function libraries:

- com.ibm.able.rules.AbleBeanLib
- com.ibm.able.rules.AbleCalendarLib
- com.ibm.able.rules.AbleDebugLib
- com.ibm.able.rules.AbleGUILib
- com.ibm.able.rules.AbleListLib
- com.ibm.able.rules.AbleMathLib
- com.ibm.able.rules.AblePredicateLib
- com.ibm.able.rules.AbleStringLib
- com.ibm.able.rules.AbleWorkingMemoryLib

Of these libraries, the highly specialized AbleCalendarLib, AbleDebugLib, AbleGUILib, AblePredicateLib, and AbleStringLib require an explicit Import statement to use their methods. The other libraries are imported automatically for you.

AbleBeanLib is experimental and may change from release to release. As of this writing, AbleBeanLib provides methods for instantiating arbitrary Java objects from rules and for calling methods on those objects. One interesting use is to write rules that create additional Able ruleset objects and then invoke those newly created rulesets. In this way, rulesets can be cascaded, calling one another and returning values. This library is built-in and does not need to be explicitly imported for its methods to be used. As always, read the JavaDoc output to see what is available. You will find examples in the AbleBeanLibDemo.rs example ruleset.

AbleCalendarLib provides methods that make it easy to do temporal reasoning. You can determine whether dates are before, after, or between other dates, and do date manipulation. To take full advantage of AbleCalendarLib, use the library with your own user-defined Calendar data type:

    Type   (Calendar: "java.util.GregorianCalendar")
    Import ("com.ibm.able.rules.AbleCalendarLib")

    Variables  ( currentTime Calendar() )
    Rules Main ( T1: currentTime = getCurrentTime() )

and so on.... You do have to explicitly import this library in order to use its methods.

AbleDebugLib provides a handy graphical debugging console that you can use to debug your rulesets when within the Able Editor environment. When enabled, you can step through your rules a clause, rule, ruleblock, or ruleset at a time. Refer to Debugging a RuleSet in this section for more information. You do have to explicitly import this library in order to use its methods.

AbleGUILib is used exclusively by backward chaining inference engines and contains methods to allow an inference engine to prompt a user to supply values of variables that can not be determined through inferencing. If you run your rule agents in an environment that allows an inference engine to interact with an end user, simply import this library to activate potential end user interaction. If you run your rule agents in an environment where it is not possible to interact with end users, do not import this library, and the inference engine will make no attempt to query a user for indeterminant variable values.

AbleListLib provides most of the function of the java.util.List interface and is provided for manipulating List variables. The methods in this library all begin with the word list which is then followed by a java.util.List method name; for example, the method addAll() becomes listAddAll(). The example source ruleset, AbleListLibDemo.rs, provides many examples of using the list library. This library is built-in and does not need to be imported for its methods to be used. For a list of available methods, read the JavaDoc output for this class.

AbleMathLib provides almost all the function of java.lang.Math to rule writers. The method names in this library are exactly the same as in the java.lang.Math class. This library is built-in and does not need to be imported for its methods to be used. For a list of available methods, read the JavaDoc output for this class. For examples of using some of the methods provided by this class, see the AbleMathLibDemo.rs example ruleset.

AblePredicateLib is useful only to predicate logic rulesets and provides a few mathematical functions designed to work with the predicate inference engine. You do have to explicitly import this library in order to use its methods.

AbleStringLib provides selected functions from java.lang.String and java.lang.StringBuffer to rule writers. The method names in this library follow those in the java.lang classes with a prefix of 'string'. You must explicitly import this library in order to use its methods. For a list of available methods, read the JavaDoc output for this class. For examples of using some of the methods provided by this class, see the AbleStringLibDemo.rs example ruleset.

AbleWorkingMemoryLib provides functions, such as assert() and retract(), to manipulate working memory from within your rules. This library is built-in and does not need to be imported for its methods to be used. For a list of available methods, read the JavaDoc output for this class.

#### Externally Attached Functions

Built-in and imported functions must exist at the time a ruleset is compiled and they occupy space in the compiled ruleset. Externally attached functions are functions that are added to a ruleset at runtime under control of some external Java program, just before the ruleset is actually processed, and the functions occupy space somewhere else in the Java virtual machine. Because the Able Rule Language compiler needs to know the names of these functions, however, you must use the UserDefinedFunctions statement to specify, by name and arity, those functions that will be attached to the ruleset at runtime. Then, if declared externally attached functions are not available when the ruleset is processed, a runtime exception is thrown.

Able's `examples/rules` directory contains the source code of an example program that attaches external functions to a ruleset and then processes the ruleset. The program's name is SampleSensorEffector.java.

Note that externally attached functions always take precedence over built-in and imported functions of the same name and arity, so you can use external functions to override the behavior of built-in and imported functions.

Return to top

### Debugging a RuleSet

To interactively debug a ruleset within the Able Editor environment, follow these steps:

- In the ruleset to be debugged, import the debug library:

  `Import("com.ibm.able.rules.AbleDebugLib")`

- At the spot within the ruleset where you want debugging to start, code something like the following:

  `DebugStart: rc = startDebugConsole(this)`

- When your ruleset is processed, and when the first startDebugConsole(this) statement is reached, a debugging console will appear on your display. The debug console contains two frames; the lefthand frame shows the inference engine's current context and the next rule to be evaluated, while the righthand frame shows trace statements from the inference engine. There are also a set of buttons on the bottom of the console that you can use to step through your ruleset at different levels of detail.

  You can control the amount of information that appears in the righthand frame by using the Trace menu item and selecting a different trace level.

  You can step through your ruleset by using either the Run menu items or the buttons on the bottom of the debug console. The menu items and buttons operate as follows:

  Clause
    Evaluates the current clause and steps to the next clause.
  Rule
    Evaluates all clauses in the current rule and steps to the next rule.
  RuleBlock
    Evaluates all rules in the current rule block and steps to the first rule of the next rule block to be evaluated. If there are no more rule blocks, the debug console will close upon completion of the inference cycle.
  Run
    Evaluates all clauses, rules, and rule blocks until the next userBreakpoint(this) statement is encountered. If no userBreakpoint(this) statement is encountered, the inference cycle runs to completion and the debug console closes.
  Quit
    Closes the debug console and the inference cycle runs to completion. However, if a new startDebugConsole(this) statement is encountered, the debug console will re-open.

- To place a breakpoint at any arbitrary location in your ruleset, use the userBreakpoint(this) or userBreakpoint(this, "textMessage") functions within your rules. For example, you mught have a rule that looks like this:

      if   a == b
      then c = d
           rc = userBreakpoint(this, "Got here!")

- To end debugging from within a ruleset, code a rule that is something like the following:

  `DebugStop: rc = stopDebugConsole(this)`

Note that the debug console will close at the end of each inference cycle even though a stopDebugConsole(this) statement hasn't been reached. Note also that a startDebugConsole(this) statement will cause the debug console to reappear at any time, even though Rule, RuleBlock, Run, or Quit is in effect.

Return to top

### Working with a RuleSet Programmatically

To create and work with a ruleset in a Java program, follow these steps:

- Create the ruleset:

  `AbleRuleSet myRuleSet = new AbleRuleSet("Name");`

- Customize the ruleset; that is, load it with variables and rules. The best way to do this is to tell the ruleset to instantiate itself from some source file written in either Able Rule Language or XML:

  `myRuleSet.instantiateFrom("sourceFile.rs", ...);`

  where `sourceFile.rs` is a source rule file you created with the Able RuleSet Editor or by hand using any text editor. You can also customize the ruleset programmatically by using the ruleset's API to dynamically create and add variables and rules, but this is very tedious and is not demonstrated here.

- Initialize the ruleset:

  `myRuleSet.init();`

  The `init()` method must be called immediately after a ruleset is instantiated or is changed by adding new variables and/or rules.

- Add data to the ruleset's input buffer, if the ruleset expects an input buffer:

      Object[] lclInpBuffer = (Object[])myRuleSet.getInputBuffer();
      lclInpBuffer[0] = new Boolean(true);
      lclInpBuffer[1] = new Double(9.9);
      lclInpBuffer[2] = "some string data";
      lclInpBuffer[3] = new Double(88.88);

- Process the ruleset:

  `myRuleSet.process();`

- Access the output of the ruleset, if any:

      Object[] lclOutBuffer = (Object[])myRuleSet.getOutputBuffer();

      for (int i=0; i<lclOutBuffer.length; i++) {
        System.out.println("!! Output element[" + i + "]: <" + lclOutBuffer[i] + ">");
      }

- Reset the ruleset for another processing round:

  `myRuleSet.reset();`

  At this point you may change the data in the ruleset's input buffer and call `process()` again, repeating the cycle as you wish.

The above code snippets demonstrate working with a ruleset at its simplest. An example Java program, SampleSensorEffector.java, is provided in Able's `examples/rules` directory and clearly shows these techniques. Of course, there are many other ways to work with rulesets, such as wiring them to input data sources and filters, sending the output to Able agents, and so on. These techniques are beyond the scope of this document.

Return to top

### Tips for Writing Rules

#### Rule Formatting

- Rules are entirely free form: a single rule may be split across multiple lines or strung into one very long line. The following two rules are equivalent:

         rule1: if Temp is very Hot then Pressure is High
         rule2: if
                   Temp is very Hot
                then
                   Pressure is High

#### Rule Labels

- Rule labels are optional and must be followed by a : (colon). Rule labels are useful for organization and when debugging rulesets. They serve no other purpose. Rule labels, if used, must be unique; that is, two rules cannot have the exact same label:

         rule4a: c = d       // Labeled rule
         rule4b  :  e=f      // Labeled rule
         rule4b  :  f=g      // causes parser exception: rule label already used!
               : a = b       // Unlabeled rule

#### List Variables

- List variables are special; please refer to this section for further information before using them.

#### Boolean Literals

- Boolean literals are the boolean keywords true and false, case insensitive.

         rule6a: someVar1 = true   // identical to below
         rule6b: someVar1 = TrUe   // identical to above

#### Numeric Literals

- Numeric literals are numbers. Numeric literals between -1.0 and +1.0 must be entered with a leading zero or a parser exception will occur:

         rule6a: numVar = 0.9      // is valid syntax
         rule6b: numVar =  .9      // causes parser exception!

- Numeric literals assigned to Continuous and Fuzzy variables must be within the variable's universe of discourse:

         Pressure continuous(-100 to +100)
         rule01: Pressure = 100    // is valid
         rule02: Pressure = 1000   // causes exception: 1000 not between -100 and 100!

#### String References

- String literals are basic strings. A string assigned to a Categorical variable must be one of the string literals defined for that variable:

         BondRating  categorical("A" "AA" "AAA")
         OtherRating categorical("ABC" "DEF")

         rule01: BondRating = "AA"   // is valid
         rule02: BondRating = "ABC"  // causes parser exception: ABC not defined for BondRating

#### Function Arguments

- Arguments to functions can be the name of a variable declared in the ruleset (always passed by value), boolean literals, numeric literals, and string literals:

         Temperature numeric(98.6)       // Declare numeric variable
         SystemId    numeric(0)          // Declare numeric variable
         UserDefinedFunctions(getTemp/1) // Declare function that takes one arg

         functionRule1 : Temperature = getTemp(SystemId) // is valid
         functionRule2 : Temperature = getTemp(1234)     // is valid

- The number and type of arguments to a function must match what is expected by the actual Java method; if either is not what is expected, an exception will occur:

         functionRule3 : Temperature = getTemp(SystemId) // may or may not be
                                        // valid depending on the number of
                                        // arguments expected by the method
                                        // represented by the function getTemp.

#### Function Return Value

- Functions may return any Java primitive or Object. However, the type must be of a kind expected by the rule, or the results may be unpredictable:

         testValue Boolean(false)        // Declare boolean variable
         UserDefinedFunctions(myTest/1)  // Declare function that takes one arg

         aRule : if testValue == myTest("123") ... // OK if myTest returns
                                                   // a boolean or Boolean

  Theoretically, myTest may return a string, but only if the string is either "true" or "false" (case insensitive); any other string will cause a runtime exception. myTest may also return a number, where 0.0 is considered false and any other number is considered true. Such uses, however, are to be thoroughly discouraged as they can lead to unexpected errors.

#### Operators

- All operators have their standard meanings. Some things to note:

  Operator | Meaning
  --- | ---
  != | not equal to; synonym of <>
  <> | not equal to; synonym of !=
  Is | fuzzy assignment or comparison, depending on context; may be used only between a Fuzzy variable reference and a fuzzy set reference belonging to the same variable; a list of hedges may precede the set reference; case insensitive.

Return to top

Able Rule Language master index.
Able RuleSet Editor master index.
Rules package table of contents.

Last modified: Wed Oct 03 10:39:11 Central Daylight Time 2001