Reference


Top     Installation     Introduction     Samples     Tutorial     Reference     Release Notes


Using Logic Relations for Advanced Pattern Matching

In addition to setting fact values, rules can specify logical relationships. Logical relationships are, in general, more abstract than other types of rules, which makes them powerful but a bit more challenging to master.

A logic relationship is specified:

name{ arg1, arg2, ..., argN } WHEN conditions

name — the name of the logic relation

arg1, arg2, ... argN — the values involved in the relation.

conditions — the conditions under which the relation is true. The conditions are optional.

Note that syntactically logic relations are distinguished from facts by the use of curly braces {} instead of parentheses () or brackets [].

For example, here are some relations that might be involved in genealogical trees:

parent{ "Dan", "Russell" }
parent{ "Dan", "Carol" }
parent{ "Ralph", "Dennis" }
parent{ "Mary", "Dan" }
parent{ "Mary", "Ralph" }
parent{ "Carol", "Jean" }
parent{ "Carol", "Michael" }

Each of these states the parent relation between two people, so Dan is the parent of Russell.

Typically, logic relations use pattern-matching variables to express general relationships. For example, this relation can be used to express a sibling (brother/sister) relationship:

sibling{ ?x, ?y } WHEN parent{ ?p, ?x } AND parent{ ?p, ?y } AND ?x <> ?y

It says the ?x and ?y are siblings when they both have the same parent, ?p. The last condition prevents the relation for being true of a person with them self.

Each of these logical relations can be used in other rules. So these two rules might also be in the rule set with the above relations:

parent = ?p WHEN parent{ ?p, person }
sibling = ?s WHEN sibling{ ?s, person}

They might be queried like this:

FIND parent AND sibling WHEN person = "Carol"

The result of the query would be: ["Dan", "Russell"]

Relations can refer to other relations. So the cousin relation will be true between two people when their parents are siblings:

cousin{ ?x, ?y } WHEN parent{ ?px, ?x } AND parent{ ?py, ?y } AND sibling{ ?px, ?py }

Logical relations are often used with FINDALL() to find an array or list of values. The following rule will find all of the cousins of a person:

cousins = FINDALL( ?c, cousin{ ?c, person } )

The query:

FIND cousins WHEN person = "Dennis"

yields ["Russell", "Carol"]

Recursion

Logic relations can recursively refer to themselves. Recursive logic relations have at least two rules. The first one specifies the simple case, and the others define the recursive cases. For example the ancestor relation can be defined recursively as:

In logic relations:

ancestor{ ?a, ?x } WHEN parent{ ?a, ?x }
ancestor{ ?a, ?x } WHEN parent{ ?y, ?x } AND ancestor{ ?a, ?y }

This can be used with FINDALL to find all of someone's ancestors:

ancestors = FINDALL( ?a, ancestor{ ?a, person } )

Lists

Lists are represented with square brackets. ex. [1,2,3,4], ["apples", "pears", "bike", "skates"]

A special syntax is used to refer to a list in two parts:

It is [ ?head | ?tail ]

The head of [1,2,3,4] is 1, and the tail is [2,3,4].

The symbol [] is used to represent an empty list.

These two syntactic elements can be used in recursive logic relations to apply a transformation to each element of a list. For example, supposed we wanted to double each number in a list of numbers.

The logic relation double would be used to express the relation between one list and a list of doubled values. The recursive rules are:

double{ [], [] }
double{ [?x | ?xs], [?xx | ?xxs] } WHEN ?xx = 2 * ?x AND double{ ?xs, ?xxs }

This can be used by the following rule and query:

double = ?d WHEN double{input, ?d }
FIND double WHEN input = [1,2,3,4]

The answer will be: [2,4,6,8]

Sometimes it is necessary to create a new list from an old one based on other rules in a rule set. Consider these facts and rules in a rule set:

fruit["pear"]
fruit["apple"]
vegetable["corn"]
edible[?x] WHEN fruit[?x] OR vegetable[?x]

Then a recursive predicate could be written to pick just the edible items from a list. It would have three rules:

edibles{ [], [] }
edibles{ [?x | ?xs], [?x | ?ys] } WHEN edible[ ?x ] AND edibles{ ?xs, ?ys }
edibles{ [?x | ?xs], ?ys } WHEN NOT edible[ ?x ] AND edibles{ ?xs, ?ys }

This rule and query can be used to pick off the edible items from a list:

edibles = ?e WHEN edibles{ input, ?e }
FIND edibles WHEN input = ["corn", "apple", "bike", "toaster", "pear"]

The answer will be: ["corn", "apple", "pear"]

Not Using Logic Relations

For most applications, it is not necessary to use recursive logic relations. For example, the list of edibles above could also have been generated using the MEMBER() function to pick elements from a list and FINDALL() to gather all the results:

edibles = FINDALL( ?e, ( ?e = MEMBER( input ) AND edible[?e] ) )

The doubles could have also been found the same way:

doubles = FINDALL( ?d, ( ?x = MEMBER( input ) AND ?d = 2 * ?x ) )

When the list transformations are more complex, however, then the added power of recursive logic relations becomes more necessary.

Open in New Window to Print


Copyright ©2005-7 Amzi! inc. All Rights Reserved.
ARulesXL and Amzi! are trademarks or registered trademarks of Amzi!
Microsoft and Excel are trademarks or registered trademarks of Microsoft Corporation.