NOTE: In the following sections describing operators and pattern types, some simple examples are used to illustrate the behavior of patterns. Many of these examples show the agent's mental model consisting of several Integer and/or String objects, and the agent's rules contain patterns that match agains Integers and/or Strings . These data types were chosen to make the examples as simple as possible. Although it's possible to use Integer and String objects as beliefs in an agent's mental model, most non-trivial agents use PAC instances to store their knowledge of the world.
The discussions in the sections below do not take refraction into account. Refraction is the term used in rule-based systems to describe the suppression of a response to repeated stimuli. This term is borrowed from neuroscience, where it refers to a neuron's response to repeated stimuli. In the AgentBuilder run-time system, a rule will be activated only if all of its left-hand-side patterns are satisfied, and at least one of the patterns matches against a new belief. Rule activation will be suppressed if all patterns match against old beliefs
Some examples show rule definitions, which contain the generic patterns, and rule activations that result from pattern matching the rules against the mental model. The rule definitions show the variables in the patterns, e.g., ?i represents a variable of type Integer with name ?i , and ?s represents a String variable. The rule activations show the values bound to the variables in each activation, with the given mental model. Only the bindings that lead to an activation of the rule are shown.
A BIND pattern is the simplest type of pattern. A BIND pattern will evaluate to true if there exists a binding for the variable in the pattern. For example, assume that ?s is a variable of type String . The pattern ( BIND ?s ) will evaluate to true , and will bind a value to the variable ?s , for every String object in the mental model. Consider the example shown in Figure 114:
Figure 114. Bind Example
This rule, with the given mental model of two new String beliefs, will fire twice in the same cycle. The pattern ( BIND ?s ) will evaluate to true twice, and each time it will bind the variable ?s to one of the String values in the mental model. The first time the rule fires it will print the string foo bar , the second time it will print yada yada yada.
Variables will bind to objects which are of the class defined for the variable, or any subclass (or subclass of a subclass, etc.) of the defined class. Consider, for example, a hierarchy of classes that represent various shapes in a graphical application. Assume that the Square class is a subclass of the Rectangle class, and the Rectangle class defines and implements a method setWidth(int) . The Square class implements its own version of setWidth(int) . The Square setWidth overrides the Rectangle setWidth and sets both the length and the width to the specified value, to maintain squareness.
In the example shown below, assume that the ?rectangle variable is defined to bind to objects of class Rectangle . The Set Widths rule will fire twice, once with ?rectangle bound to the Square instance, once with ?rectangle bound to the Rectangle instance. When ?rectangle is bound to the Square s1 the Square method setWidth(int) will be used to perform the specified action. When ?rectangle is bound to the Rectangle r1 the Rectangle method setWidth(int) will be used.
MENTAL MODEL: Square<s1> Rectangle<r1>
RULE: Set Widths IF (BIND ?rectangle) THEN DO ?rectangle.setWidth(42)
See the BIND patterns vs. EXISTS patterns section below for an explanation of BIND patterns in some unusual contexts.
The EQUALS operator is used to perform an equality comparison between two objects of the same class, using the equals method defined in the class of the objects. For example, consider a pattern that compares a String variable and a String literal: ( ?string EQUALS "yada yada yada" ). When this pattern gets evaluated the agent engine will find all possible bindings for the ?string variable then invoke the String::equals(String) method on each binding, using the String literal yada yada yada as the argument
The NOT_EQUALS operator is used to perform an inequality comparison between two objects of the same class, using the equals method defined in the class of the objects but with a false expected value.
The numerical relation symbols =, !=, <, <=, >, and >= can only be used between numerical operands. The numerical operands can be any numerical objects or primitive values, and the types of the two operands do not need to be the same. For the following examples assume that ?i is an Integer variable and ?f is a Float variable. The following patterns are all correct patterns: (?i = 23) , (23.4<= ?f) , and (?i = ?f) . Note that these example patterns would not be used together in the same rule, because they are mutually exclusive conditions. The last example shows a comparison between an Integer and a Float , which will evaluate to true if both objects contain the same value.
It's also possible to compare the values in numerical objects (e.g., Integers or Floats ) to primitive values extracted from objects in the mental state. For example, assume a PriceQuote PAC has an attribute named quantity which is an int value, assume ?priceQuote is a variable of type PriceQuote , and assume currentQuantity is a named instance of Integer . Then ( ?priceQuote.quantity <= currentQuantity ) is a valid numerical pattern, even though it compares an int to an Integer . Numerical patterns may contain any mixture of numerical objects or numerical primitive values; the values are automatically extracted from the objects and used in the comparison. In numerical relations there's no need to invoke methods (intValue(), floatValue(), etc .) to extract values from an object before the values are used in a comparison.
It's possible to compare numerical objects with the EQUALS or NOT_EQUALS operator but the types of both objects must agree. If ?i is an Integer variable and 23 is an Integer value, then the pattern ( ?i EQUALS 23 ) is a valid pattern which will have the same truth value as the numerical relation pattern ( ?i = 23 ) . It's not possible to mix object types in a pattern with an EQUALS operator, so if 23.0 is a Float value then a pattern such as ( ?i EQUALS 23.0 ) is not a valid pattern. For comparisons of numerical objects the numerical relation patterns (i.e., using = or != ) are recommended.
NOTE: In a LHS pattern the equal sign, = , represents an equality comparison between numerical objects or values. In a LHS pattern it does not represent assignment of a value to a variable, as it would in a programming language such as C or Java. The LHS pattern ( ?i = 23 ) compares the bindings for ?i to the integer value 23 . It does not assign a value of 23 to the variable ?i . The pattern binds to the value 23 if and only if there is an Integer in the mental model with the value 23 .
The arithmetic operators +, -, *, and / require numerical operands. The types of the operands may differ, as long as both are numeric types. If the types of both operands are the same then the type of the result will be the same as the operand types. Otherwise the result type will automatically be the larger of the operand types. For example Long+Integer returns a Long , Float+Integer returns a Float , Float+Double returns a Double .
If the operation is division and both operands are integral types ( Integer, Short, Long, or Byte , or their primitive counterparts) then integer division will be used (e.g., 5 / 2 yields 2 ). If the operation is division and either or both operands are non-integral types then floating-point division will be used (e.g., 5.0 / 2 yields 2.5 ).
The boolean operators AND , OR , and NOT can be applied to any patterns. Use of the AND operator is fairly straightforward: an AND pattern is true if and only if both of its subpatterns are true. The NOT operator also behaves as expected: a NOT pattern is true if and only if its subpattern is false. (See the BIND patterns vs. EXISTS patterns section below for a description of a pattern where NOT may perform differently than expected.)
Rules with OR patterns may fire less often or more often than expected and should be used with caution. The following examples illustrate the behavior that can be expected from OR patterns.
The first example shows a mental model consisting only of several Integer objects with instance names (e.g., i1 ) which are not used here. Rule 1 will fire once for each Integer object in the belief base which has a value less than 2 and greater than or equal to 4 . This is an example of an OR pattern which behaves as expected. See Figure 115.
Figure 115. Example Use of OR
As expected, Rule 1 fires twice because there are two bindings which satisfy the pattern ((?i < 2) OR (?i >= 4)) . The two successful bindings are shown in the list of rule activations; the unsuccessful bindings (i.e., the bindings to 2 and 3) caused the evaluation to fail and so they do not appear in the list of activations.
This example shows the unusual behavior that is possible in OR patterns when different variables are used in the clauses. Given the mental model shown below, Rule 2 fires twice even though there is only one Integer that satisfies the first clause of the OR pattern. See Figure 116 for an example.
This example shows the behavior that is possible in OR patterns when the clauses are not mutually exclusive. Given the mental model shown in Figure 117, Rule 3 fires THREE times.
Figure 117. Another Example Use of OR
The OR pattern gets tested with each possible pair of bindings, i.e., with the ordered pairs (1,abc) , (2,abc) , (1,xyz) , and (2,xyz) . Three of these pairs cause the OR pattern to evaluate to true, so the rule is activated three times. Only the (1,xyz) pair causes both clauses of the OR pattern to be false, so it doesn't appear in the list of activations.
Quantified patterns are patterns containing one or more quantified variables, which are marked with the EXISTS or FOR_ALL keywords. The EXISTS keyword marks a variable as existentially quantified; the FOR_ALL keyword marks a variable as universally quantified. NOTE: The scope of quantified variables is restricted to the quantified pattern. A quantified variable cannot be used in more than one pattern in a rule. The following example in Figure 118 shows an incorrect usage:
Figure 118. An Incorrect Example
In this incorrect example the same variable is used in a quantified pattern (the first pattern) and in the second pattern. This is disallowed because the scope of the quantified variable ?i is restricted to the quantified pattern. Using the same variable elsewhere in the rule implies a connection between the two usages of ?i , but there is no connection because of the restricted scope of the quantified variable.
A FOR_ALL pattern will activate a rule once if all bindings for the quantified variable(s) satisfy its subpattern. The behavior of this type of pattern is fairly straightforward in most usages, but special care must be taken when mixing quantified variables with non-quantified variables.
An EXISTS pattern will activate a rule once if there are one or more bindings for the quantified variable(s) which satisfy the subpattern in the EXISTS pattern. The behavior of this type of pattern is fairly straightforward in most usages, but special care must be taken when mixing quantified variables with non-quantified variables. The examples below show the behavior of several types of EXISTS patterns.
All examples use the following simplified example mental model of Figure 119, which consists of several Integer objects and String objects, some of which are named instances.
Figure 119. Example Mental Model
Rule 1 contains a regular object pattern (i.e., not a quantified pattern). The rule will be activated once for every Integer object in the belief base which is greater than or equal to 0 , so Rule 1 will be activated twice. See Figure 120.
Figure 120. Example Rule 1
In Rule 2, the object pattern from Rule 1 is now a subpattern in an EXISTS pattern. Rule 2 will be activated only once, even though there are two Integer objects in the mental model which satisfy the test in the subpattern. The variable ?i is a quantified variable so it doesn't matter how many bindings will satisfy the test in the subpattern, as long as there is at least one. The mental model could contain hundreds of Integer objects with non-negative values and Rule 2 would still fire only once. Rule 2 is shown in Figure 121.
Figure 121. Example Rule 2
Rules 3 and 4 are examples of badly-written rules. In each case the quantified variable (i.e., the Float variable ?f in Rule 3, and the String variable ?s in Rule 4) doesn't match the variable in the subpattern. The pattern in Rule 3 asks the question:
Does there exist a Float object in the mental model such that there is a String object in the mental model equal to abc ? See Rule 3 in Figure 122.
Figure 122. Example Rule 3
This pattern is not satisfied by any combination of objects in the mental model, because there are no Float objects, so Rule 3 will not fire at all. The fact that the subpattern is satisfied (twice) doesn't matter--evaluation is halted due to the lack of a binding for the Float variable.
The pattern in Rule 4 asks the question:
Does there exist a String object in the mental model such that there is an Integer object in the mental model with a non-negative value?
Figure 123. Rule 4 with a Bad Pattern
The pattern in Rule 4 in Figure 123 also has a mismatch between the quantified variable and the variable in the subpattern, but Rule 4 will fire twice. There is at least one binding for a String variable (even though the value is not tested at all) and there are two Integer bindings that satisfy the test in the subpattern, so the rule is fired twice. Rules 4b and 4c are shown for comparison. The pattern in Rule 4b is equivalent to the pattern in Rule 4, for this mental model. (In general they are not equivalent). For this example mental model, Rule 4b will fire twice and Rule 4c will fire four times. These rules are shown here for comparison with Rule 4, to show why Rule 4 fires twice given the example belief base.
There are situations where rules such as Rule 4b or Rule 4c are used in correct programs. It's possible and sometimes useful to mix quantified variables and non-quantified variables in subpatterns, as was done in Rule 4b. The pattern in Rule 5 asks the question:
Does there exist (at least one) PriceQuote object for every Product object in the mental model?
Figure 124. Example Rule 5
This rule will fire once for every Product in the mental model which has at least one PriceQuote associated with it (based on a comparison of the names in each object). In this pattern the Product variable ?p is not quantified, the PriceQuote variable ?q is quantified. This type of pattern would be used in situations where you want to fire the rule if there is at least one PriceQuote for a Product , but you don't want the rule to fire more than once if there are multiple PriceQuotes associated with the same Product .
Some quantified patterns may evaluate to true in situations where there are no matching beliefs. For example, consider the following mental model and the two example rules shown in Figure 125:
Figure 125. Vacuously True Quantified Patterns
Rule 1 asks the question: Is it true that every Float in the mental model has a value less than 3 ?
The answer is yes because there are no Float objects in the belief base, hence there are no Float objects that could fail the test in the subpattern. In logic this kind of pattern is labeled "vacuously true", because the truth value of the pattern depends on the fact that there are no elements to test. In the AgentBuilder run-time system the pattern will evaluate to true (in this particular example), but the activation of the rule will be suppressed because of refraction.
Rule 2 is equivalent to Rule 1; Rule 2 asks the question: Is it true that there does not exist a Float in the mental model with a value greater than or equal to 3 ?
This is of course true because there are no Floats in the mental model, hence there are no Floats with value >= 3 . The pattern in Rule 2 also evaluates to true (in this particular example) but the activation of the rule is also suppressed because of refraction.
To ensure that the the rules get activated, modify rules 1 and 2 by adding a pattern that will always bind to a new belief. Rules 1b and 2b show the modified rules 1 and 2, with the added BIND pattern. The added pattern binds the built-in currentTime instance which is maintained by the run-time system and which is guaranteed to be a new belief each cycle. Therefore the activation of rules 1b and 2b will not be suppressed by refraction. The rules will be activated whenever their first patterns evaluate to true. See Figure 126.
Figure 126. Ensuring Rule Activation
A BIND pattern will contribute to the activation of a rule once per new matching belief object. An EXISTS pattern will contribute to a single activation if there is at least one new matching belief object. The example shown in will make this more clear. In this first example assume all the Integer objects have been stored into the mental model during the last cycle, so we don't need to worry about refraction (yet).
Figure 127. Example 1. More on Binding and Existentials
Rule 1 shows a BIND pattern with an Integer variable. This the simplest type of pattern. A BIND pattern is satisfied if there exists a binding for its variable. Given the mental model containing two Integer objects, Rule 1 will fire three times, once for each Integer binding.
Rule 2 shows an EXISTS pattern enclosing a BIND pattern. Given the same mental model Rule 2 will only fire once. Rule 2 will fire once regardless of the number of Integer objects in the mental model, as long as there is at least one new Integer object.
Testing for the absence of an object involves a problem due to refraction. The activation of a rule will be suppressed if there is not at least one matching new belief used in at least one of the patterns. A simple rule such as Rule 4 will never be activated because the only time the pattern is satisfied is when there are no matching objects, hence there are no new matching objects to satisfy the refraction test. Rule 5 shows the recommended way to test for the absence of an object. The (BIND currentTime) pattern will always be satisfied because the currentTime maned instance is a built-in object in the mental model. And the currentTime instance is always a new belief every cycle, so any rule containing a pattern such as (BIND currentTime) will never have its activation suppressed due to refraction. See Figure 128.
Figure 128. Rule 5 - the Final Example