This section covers some miscellaneous topics dealing with ABLE rulesets.
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.
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.
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.
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:
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.
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 topTo interactively debug a ruleset within the Able Editor environment, follow these steps:
Import("com.ibm.able.rules.AbleDebugLib")
DebugStart: rc = startDebugConsole(this)
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:
if a == b then c = d rc = userBreakpoint(this, "Got here!")
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 topTo create and work with a ruleset in a Java program, follow these steps:
AbleRuleSet myRuleSet = new AbleRuleSet("Name");
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.
myRuleSet.init();
The init()
method must be called immediately
after a ruleset is instantiated or is changed by adding new
variables and/or rules.
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);
myRuleSet.process();
Object[] lclOutBuffer = (Object[])myRuleSet.getOutputBuffer(); for (int i=0; i<lclOutBuffer.length; i++) { System.out.println("!! Output element[" + i + "]: <" + lclOutBuffer[i] + ">"); }
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.
rule1: if Temp is very Hot then Pressure is High rule2: if Temp is very Hot then Pressure is High
rule4a: c = d // Labeled rule rule4b : e=f // Labeled rule rule4b : f=g // causes parser exception: rule label already used! : a = b // Unlabeled rule
rule6a: someVar1 = true // identical to below rule6b: someVar1 = TrUe // identical to above
rule6a: numVar = 0.9 // is valid syntax rule6b: numVar = .9 // causes parser exception!
Pressure continuous(-100 to +100) rule01: Pressure = 100 // is valid rule02: Pressure = 1000 // causes exception: 1000 not between -100 and 100!
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
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
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.
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 BooleanTheoretically, 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.
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. |