All rule statements within a ruleset are grouped within one or more rule block statements.
RuleSet <nameOfRuleSet> ( <Processing Options Statement>* // Zero or more statements Variables( <Variable Declaration Statement>+ // One or more statements ) GoalVariable ( <variableName> ) // Backward chaining only InputVariables ( <variableName>* ) // Exactly one statement, zero or more names OutputVariables( <variableName>* ) // Exactly one statement, zero or more names UserDefinedFunctions ( <name/arity>* )* // Zero or more statements, zero or more names Rules <nameOfRuleBlock> ( <rule>+ // One or more rules in a rule block )+ // One or more rule blocks ) ;End of ruleset |
Able provides many different types of rules, from simple
assertion statements, to If-Then rules, to more complex
When-Do pattern matching rules. Rules in most rule
blocks are processed sequentially, so the order in which you
enter them is important. Rules appearing in the
MAIN
rule block are always processed in an
order that is determined by the inference engine, so it doesn't
matter at all what order is used.
All rules may have a priority, but not all inference engines use the priority, even if specified. Other inference engines rely on priority to do a good job. Rules may also have a label, but these are only for the author's use; they are completely ignored by the inference engines.
The number of rules you can have in a rule block is limited only by the amount of memory you have in your computer.
Return to top
Syntax
<label> <[priority]> : <ruleBody> |
Parameters
Example
. . . Rules <nameOfRuleBlock> ( A1: someVar = someOtherVar // Label is...... 'A1' // Priority is... omitted, defaults to 1.0 // RuleBody is... 'someVar = someOtherVar' r2 [5] : if someVar == true then x=y // Label is...... 'r2' // Priority is... '5' // RuleBody is... 'if someVar == true then x=y' :female=false // Label is...... omitted // Priority is... omitted // RuleBody is... 'female=false' ) . . . |
The body of a rule can be one of several different types. The basic rule bodies are:
Assertions are simply assignment statements. Since the inference engines evaluate all assertions before evaluating any conditional rules, you can use assertions to give initial values to variables. However, if you use assertions simply to assign initial values to variables, it is preferable, in most cases, to accomplish this through an external input buffer (and values assigned in this way always take precedence over any assertion rules in a ruleset).
There are two useful ways to use assertions:
Syntax
See Assignment Clauses
Example
Rules <nameOfRuleBlock> ( A1: someVar = someOtherVar // Label, but no priority :isMale=determineIfMale(person) // Neither label nor priority ) |
If-Then rules are evaluated conditionally, based on known data. The order of evaluation is determined by the inference engine, but if your ruleset is a pure fuzzy ruleset, all rules are essentially evaluated in parallel, each rule playing a part in the solution.
If-Then rules have any number of antecedent clauses separated by the keyword and (case insensitive), and one or more consequent clauses appearing in the Then part of the rule. The Else part of the rule is optional and, if present, contains one or more clauses.
Syntax
If <comparisonClause>+ Then <assignmentClause>+ Else <assignmentClause>+ |
Parameters
Example
Rules <nameOfRuleBlock> ( Test_the_Temperature: // Label, no priority if temp is very hot and // Comparison clause, connector 'and' switch == "on" [0.5] // Comparison clause then pressure is high // Assignment clause F1: if a>=b then c=d : if c < d then x = z(parm1, parm2) ) |
When-Do rules are evaluated conditionally, based on known data. The order of evaluation is determined by the inference engine.
When-Do rules may have any number of pattern match clauses separated by the keyword and (case insensitive), and multiple assignment clauses.
Syntax
When ( <patternMatchClause>+ ) Do ( <assignmentClause>+ ) |
Parameters
Example
Rules <nameOfRuleBlock> ( . . . : When ( p Puzzle ( // There must exist some Puzzle 'p' such that p.level == "hard", // p's level is equal to 'hard' and p.start == postN // p's start is equal to the value of variable 'postN' ) & r Ring ( // There must exist some Ring 'r' such that r.diam > 0 // r's diameter is greater than zero ) ) Do ( solution.level = p.level solution.ringSize = r.diam ) . . . ) |
Predicate rules are valid only in rulesets whose InferenceMethod is set to Predicate.
Syntax
<predicateClause> // Fact <predicateClause> <- <clause>+ // Rule |
Parameters
Example
Rules <nameOfRuleBlock> ( InferenceMethod(Predicate) Predicates(male, female) Predicates(father mother parent) Predicates(son, daughter, brother) GoalPredicate ( brother(milcah,X) ) // Who is the brother of Milcah? . . . Rules ( : father(abraham, isaac) // Abraham is the father of Issac : father(haran, lot) // Haran is the father of Lot : father(haran, milcah) // Haran is the father of Milcah : father(haran, yiscah) // Haran is the father of Yiscah : male(isaac) // Issac is male : male(lot) // Lot is male : female(milcah) // Milcah is female : female(yiscah) // Yiscah is female R1: son (X, Y) <- male(X) & father(Y, X) R2: daughter(X, Y) <- female(X) & father(Y, X) R3: brother (X, Y) <- male(Y) & parent(P,X) & parent(P, Y) & X != Y R4: parent (X, Y) <- father(X, Y) R5: parent (X, Y) <- mother(X, Y) ) ) |
While-Do rules are looping rules, evaluated conditionally, based on known data. The test conditions are evaluated, and, if true, the body of the rule is processed. The cycle repeats until the test conditions are no longer true.
While-Do rules have any number of test conditions separated by the keyword and (case insensitive) in the While part of the rule, and one or more consequent clauses appearing in the Do part of the rule.
Syntax
While ( <comparisonClause>* ) Do ( <assignmentClause>+ ) |
Parameters
Example
Rules <nameOfRuleBlock> ( Check_and_Lower_Temp: // Label, no priority While ( temp >= 212 and // Comparison clause, connector 'and' switch == "on" // Comparison clause ) Do ( rc = invokeRuleBlock("lowerTemp") // Assignment clause ) ) |
In the above example it is to be hoped that the invoked rule block, lowerTemp, will set the global variable temp to a new temperature, or set the global variable switch to "off".
Return to topDo-Until rules are looping rules, evaluated at least once. The Do body of the rule is always processed first and then the test conditions are evaluated. If the test conditions are true, the cycle repeats until the test conditions are no longer true.
Do-Until rules have any number of test conditions separated by the keyword and (case insensitive) in the Until part of the rule, and one or more consequent clauses appearing in the Do part of the rule.
Syntax
Until ( <comparisonClause>* ) Do ( <assignmentClause>+ ) |
Parameters
Example
Rules <nameOfRuleBlock> ( Check_and_Lower_Temp: // Label, no priority Until ( temp >= 212 and // Comparison clause, connector 'and' switch == "on" // Comparison clause ) Do ( rc = invokeRuleBlock("lowerTemp") // Assignment clause ) ) |
In the above example it is to be hoped that the invoked rule block, lowerTemp, will set the global variable temp to a new temperature, or set the global variable switch to "off".
Return to topAll rules are made up of clauses. The basic clauses are:
Assignment clauses are used to assign a value to some variable; therefore, only a variable may appear on the lefthand side of an assignment clause. The righthand side of an assignment clause can be one of several things, but not all combinations are allowable. For example, a numeric variable cannot be assigned from a boolean literal.
booleanVariable = variable | typedVariable.field | functionName(arg*) | booleanLiteral categoricalVariable = typedVariable.field | functionName(arg*) | stringLiteral continuousVariable = typedVariable.field | functionName(arg*) | numericLiteral discreteVariable = typedVariable.field | functionName(arg*) | numericLiteral fuzzyVariable = typedVariable.field | functionName(arg*) | numericLiteral fuzzyVariable Is hedge* fuzzySet listVariable = variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral numericVariable = variable | typedVariable.field | functionName(arg*) | numericLiteral objectVariable = variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral stringVariable = variable | typedVariable.field | functionName(arg*) | stringLiteral typedVariable = variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral typedVariable.field = variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral |
Comparison clauses are used to test the current value of one object against the current value of another object. All of the usual comparison operators are available and have their standard meanings.
Comparison clauses can be suffixed by an optional
WEIGHT
, which is a number between 0.0 and 1.0.
Weights are used by only the fuzzy inference engines, and can
keep a boolean comparison from wildly skewing a fuzzy result.
Weights are ignored by other inference engines. When omitted, a
clause's default weight is 1.0.
Note that <> can be used in place of != for "not equal to".
booleanVariable ( == | != ) (variable | typedVariable.field | functionName(arg*) | booleanLiteral ) weight booleanLiteral ( == | != ) (variable | typedVariable.field | functionName(arg*) | booleanLiteral ) weight categoricalVariable ( == | != ) ( typedVariable.field | functionName(arg*) | stringLiteral) weight continuousVariable ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | numericLiteral ) weight discreteVariable ( == | != ) ( typedVariable.field | functionName(arg*) | numericLiteral ) weight functionValue ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | numericLiteral | stringLiteral) weight fuzzyVariable ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | numericLiteral ) weight fuzzyVariable Is hedge* fuzzySet listVariable ( == | != ) (variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral) weight numericVariable ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | numericLiteral ) weight numericLiteral ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | numericLiteral ) weight objectVariable ( == | != ) (variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral) weight stringVariable ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | stringLiteral) weight stringLiteral ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | stringLiteral) weight typedVariable ( == | != ) (variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral) weight typedVariable.field ( == | != | < | <= | > | >= ) (variable | typedVariable.field | functionName(arg*) | booleanLiteral | numericLiteral | stringLiteral) weight |
Pattern match clauses look for the existence of variables such that the listed conditions are true.
Syntax
<variableName> <dataType> [!] ( <comparisonClause>* ) |
Parameters
Examples
p Puzzle ( // There must exist some Puzzle 'p' such that p.level == "hard", // p's level is equal to 'hard' and p.start == postN // p's start is equal to the value of variable 'postN' ) |
p Puzzle ! ( // There must not exist some Puzzle 'p' such that p.level == "hard", // p's level is equal to 'hard' and p.start == postN // p's start is equal to the value of variable 'postN' ) |
p Puzzle ( // All puzzles are selected. ) |
Syntax
<predicateName> ( <arg>* ) |
Parameters
There are some special predicate names:
Predicates can take any number of arguments. Arguments may be any of:
Examples
foo() // No args foo(X) // Local variable 'X' foo(bar, baz) // Either global vars or simple symbols foo( [a, b | c] ) // A list of 2 elements followed by any number of additional elements foo(X, _, bar(Y), "3", 4.4, true, z, [a,b] ) // Something for everyone! |
The following hedges are available for qualifying a fuzzy set in a fuzzy clause. Multiple hedges may be used in any combination, but the rule author must be fully aware of what each hedge can do to the shape of a fuzzy set.
Approximation Hedges -- useful for all bell-shaped sets | |
CloseTo (1.2) | Narrow approximation. |
About (2.0) | General approximation; slightly broadens the fuzzy region |
InVicinityOf (4.0) | Broad approximation; produces a very wide fuzzy space. |
Restriction Hedges | ||
Above | Useful for decreasing linear and sigmoidal sets and for all bell-shaped sets; do not use with increasing linear and sigmoidal sets. | ![]() |
Below | Useful for increasing linear and sigmoidal sets and for all bell-shaped sets; do not use with decreasing linear and sigmoidal sets. | ![]() |
Concentration Hedges -- these hedges depress the surface of linear sets and concentrate or intensify bell-shaped sets; the candidate space is reduced; a domain element must occur farther to the right for an equivalent truth value. | ||
Very (2.0) | ![]() |
|
Extremely (3.0) | ![]() |
Dilution Hedges -- these hedges raise the surface of linear sets and dilute bell-shaped sets; the candidate space is increased; a domain element must occur farther to the left for an equivalent truth value. | ||
Somewhat (0.5) | Complement of very. | ![]() |
Slightly (0.3) | ![]() |
Contrast Intensification Hedge | ||
Positively (n2) | Truth values less than .5 are decreased, truth values greater than .5 are increased; complement of generally. | ![]() |
Contrast Diffusion Hedge | ||
Generally (n0.5) | Truth values less than .5 are increased, truth values greater than .5 are decreased; complement of positively. | ![]() |
Negation Hedge | ||
Not | The fuzzy region is inversed. | ![]() |