home *** CD-ROM | disk | FTP | other *** search
- Chapter 7 Let's Be Logical
-
-
-
-
- In this chapter, you will learn how CLIPS deals with logical relations and
- comparisons. There are many useful applications of logical operations,
- especially when you write programs dealing with symbolic information.
-
-
- Three Into One Will Go
-
-
- So far all the rules you've seen have an implicit logical AND between the
- conditional elements. That is, a rule will not be triggered unless
- all of the conditional elements are true. However, CLIPS also gives you the
- capability of specifying explicitly logical AND conditions and
- also logical OR conditions on the LHS.
- As an example of OR, let's first look at the following rules which are
- written without an OR and then see how to rewrite them with an OR.
-
- (defrule dont-walk
- (light red)
- =>
- (printout "Don't walk" crlf))
-
- (defrule dont-walk
- (walk-sign dont walk)
- =>
- (printout "Don't walk" crlf))
-
- (defrule dont-walk
- (police say dont walk)
- =>
- (printout "Don't walk" crlf))
-
- Rather than writing three separate rules, they can all be combined into the
- following OR rule.
-
- (defrule dont-walk
- (or
- (light red)
- (walk-sign dont walk)
- (police say dont walk))
- =>
- (printout "Don't walk" crlf))
-
- The group of conditional elements enclosed within the OR element is called a
- logic block. The one OR rule is equivalent to the three rules
- above. Enter the OR rule and assert the three facts. If you check the
- agenda, you'll see that the rule is triggered three times with each
- of the facts.
- Other conditional elements can be included outside the OR conditional and
- will be part of the implicit AND. For example, if the OR rule was
-
- (defrule dont-walk
- (status walking)
- (or
- (light red)
- (walk-sign dont walk)
- (police say dont walk))
- =>
- (printout "Don't walk" crlf))
-
- the result would be equivalent to the three rules following.
-
- (defrule dont-walk1
- (status walking)
- (light red)
- =>
- (printout "Don't walk" crlf))
-
- (defrule dont-walk2
- (status walking)
- (walk-sign dont walk)
- =>
- (printout "Don't walk" crlf))
-
- (defrule dont-walk3
- (status walking)
- (police say dont walk)
- =>
- (printout "Don't walk" crlf))
-
- As you can see, the OR is similar to a true logical OR. In a true logical
- OR, the rule dont-walk would only be triggered once if one or more
- conditions are true. However, in the OR of CLIPS, the dont-walk rule will be
- triggered for each OR conditional element that is true, since
- the one OR rule is equivalent to three rules. However, an OR rule does
- function like a true logical OR in the sense that if any conditional
- element matches a fact, then the rule will be triggered.
- Since multiple triggerings of an OR will occur with multiple facts, a
- natural question is how to prevent the problem of more than one triggering.
- For example, we don't want multiple printouts of "Don't walk" appearing for
- multiple facts. After all, the robot only deals with one traffic
- light at a time. Just because multiple facts may be true about the traffic
- light doesn't mean we want a printout of "Don't walk" for each fact.
- One possible solution to multiple triggerings you might think of is to
- retract all the triggering facts when the rule fires once. If all
- of the other triggering facts of the OR are retracted, the rule won't be
- triggered again. For example,
- (defrule dont-walk
- (or
- ?fact <- (light red)
- ?fact <- (walk-sign dont walk)
- ?fact <- (police say dont walk))
- =>
- (retract ?fact)
- (printout "Don't walk" crlf))
-
- Notice that all conditional elements are bound to the same variable, ?fact.
- At first, you may think this an error since you'd never assign
- the same variable to conditional elements of an ordinary rule. But an OR rule
- is different. Since an OR is equivalent to multiple rules, the
- above rule is equivalent to the following three rules.
-
- (defrule dont-walk1
- (status walking)
- ?fact <- (light red)
- =>
- (retract ?fact)
- (printout "Don't walk" crlf))
-
- (defrule dont-walk2
- (status walking)
- ?fact <- (walk-sign dont walk)
- =>
- (retract ?fact)
- (printout "Don't walk" crlf))
-
- (defrule dont-walk3
- (status walking)
- ?fact <- (police say dont walk)
- =>
- (retract ?fact)
- (printout "Don't walk" crlf))
-
- By looking at the three rules, you can see that the same variable name was
- necessary to match the (retract ?fact) action. For example, suppose
- you had assigned separate names to the conditional elements such as ?light,
- ?walk, and ?police and then used a (retract ?light ?walk ?police).
-
- (defrule dont-walk
- (status walking)
- (or
- ?light <- (light red)
- ?walk <- (walk-sign dont walk)
- ?police <- (police say dont walk))
- =>
- (retract ?light ?walk ?police)
- (printout "Don't walk" crlf))
-
- The (retract ?light ?walk ?police) would be in error because two out of
- three variables would not be defined in the equivalent rules.
- Even though our rule does retract multiple facts, it still prints out
- multiple "Don't walk" messages because the one rule is exactly the same
- as three rules. Try it and see.
- The correct solution to prevent multiple messages is to define a control
- fact. Consider the following program.
-
- (defrule dont-walk
- ?control <- (control-fact)
- (status walking)
- (or
- ?fact <- (light red)
- ?fact <- (walk-sign dont walk)
- ?fact <- (police say dont walk))
- =>
- (retract ?control ?fact)
- (printout "Don't walk" crlf))
-
- If the control fact is retracted, the rule cannot fire again. It's as if
- you retracted the (status walking) fact. Strictly speaking, we
- don't even need to retract the ?fact. However, it's a good idea to retract
- all facts that characterize the current light situation so that
- the facts don't hang around and accidentally cause a firing if the control
- fact is re-asserted.
- That is, what if the robot wanders on and encounters another light. You don't
- want the old light's facts in memory.
-
-
- And What's More
-
-
- The logical AND is opposite in concept to the logical OR. Instead of any
- conditional elements triggering a rule, the AND requires that all of
- the conditional elements be matched to facts.
- Normally there is an implicit AND for the conditional elements of a rule. A
- rule such as
-
- (defrule and-test
- (status walking)
- (walk-sign walk)
- =>
- (printout "Walk" crlf))
-
- could also be written with an explicit AND as
-
- (defrule and-test
- (and
- (status walking)
- (walk-sign walk))
- =>
- (printout "Walk" crlf))
-
- where the indentations are just to aid readability.
- Of course, there is no advantage to writing a rule with an explicit AND.
- It's more efficient to use the implicit AND of conditional elements
- if you don't need to specify an AND.
- The AND is provided so that you can use it with the other logical functions
- to make more powerful patterns. For example, it can be used with
- an OR to require groups of multiple conditions be true, as shown in the
- following example.
-
- (defrule walk
- (or (police says walk)
- (and (walk-sign walk)
- (light green))
- (and (walk-sign walk)
- (light yellow)))
- =>
- (printout "Walk" crlf))
-
- Enter this rule and assert the facts
-
- (police says walk)
- (walk-sign walk)
- (light green)
- (light yellow)
-
- When you check facts, you'll see
-
- f-0 (initial-fact)
- f-1 (police says walk)
- f-2 (walk-sign walk)
- f-3 (light green)
- f-4 (light yellow)
-
- Now check the agenda. The rule will be triggered with the facts as shown
- following.
-
- 0 walk f-2 f-4
- 0 walk f-2 f-3
- 0 walk f-1
-
- So the one rule called walk is equivalent to the three following rules,
- where the comments identify the triggering facts.
-
- (defrule walk
- (walk-sign walk) ; f-2 and f-4
- (light yellow)
- =>
- (printout "Walk" crlf))
-
- (defrule walk
- (walk-sign walk) ; f-2 and f-3
- (light green))
- =>
- (printout "Walk" crlf))
-
- (defrule walk
- (police says walk) ; f-1
- =>
- (printout "Walk" crlf))
-
-
- Not My Constraint
-
-
- The previous rule are simplified ones that don't cover all cases such as the
- breakdown of the traffic-light. For example, what does the robot
- do if the light is red or yellow and the walk-sign says walk?
- One way of handling this case is to use a field constraint to restrict the
- values a pattern may have on the LHS. The field constraints put
- limits on the values a pattern may have on the LHS.
- There are two types of constraints. The first type is called a logical
- constraint. There are three types of logical constraints. The first
- type of logical constraint is called a negation constraint. It's symbol is
- the "~", called the tilde. The negation is a prefix constraint
- acts on the one value that immediately follows it.
- As a simple example of negation, suppose you wanted to write a very
- conservative rule which would print out "Don't walk" if the light was
- not green. This constraint is not the same as saying there is no fact (light
- green) and so a (not) is not appropriate. One approach would
- be to write rules for every possible light condition, such as yellow, red,
- blinking yellow, binking red and so forth. However, a much easier
- approach is to use the negation constraint, "~", as shown in the following
- rule.
-
- (defrule walk
- (light ~green)
- =>
- (printout "Don't walk" crlf))
-
- By using the negation constraint, this one rule does the work of many others
- that required specifying each light condition.
- Note that you cannot use the "!" and "!=" functions or any other RHS
- functions on LHS patterns. Likewise, the logical constraints cannot
- be used on the RHS.
-
-
- Be Cautious
-
-
- The second logical constraint is the OR constraint. The OR constraint is
- represented by the symbol "|", called the bar, and is an infix constraint.
- The OR constraint is used to allow any value in a pattern to match.
- For example, suppose you wanted a rule which printed out "Be cautious" if
- the light was yellow or blinking yellow. Here's how it's done using
- the "|" constraint.
-
- (defrule cautious
- (light yellow|blinking-yellow)
- =>
- (printout "Be cautious" crlf))
-
- Enter this rule and then assert (light yellow) and (light blinking-yellow).
- Check the agenda and you'll see that the rule is on the agenda
- for each fact. Also, notice that the field blinking-yellow is connected by a
- dash. Since the logical constraints operate on single fields,
- you can't have (light yellow|blinking yellow) because then the constraint
- would only be on yellow and blinking.
-
-
- YAA
-
-
- The third type of logical constraint is yet another and, the AND constraint.
- Its symbol is the "&", called the ampersand, and is an infix constraint.
- The "&" constraint is normally used only with the other constraints since
- otherwise it's not of much practical use.
- To understand where it's useful, let's first look at an example in which the
- "&" is not useful.
-
- (defrule green-light
- (light green&red)
- =>
- (printout "Go" crlf))
-
- This rule will never be triggered since there is no possible fact whose
- light is both green and red. The conditional element will not match
- on green, red, or even greenred.
- Here's another example of where the "&" is useless.
-
- (defrule green-light
- (light green&~red)
- =>
- (printout "Go" crlf))
-
- The conditional element will match a light whose color is green and not red.
- In this case, the rule can be triggered by the fact (light green)
- since green is green and not red. However, it's much more efficient to just
- write the rule as
-
- (defrule green-light
- (light green)
- =>
- (printout "Go" crlf))
-
- since a light that is green cannot be red anyway.
- Now let's see an example in which the "&" is useful. Suppose you want to
- have a rule which will be triggered by a fact which is yellow or
- blinking yellow. That's easy enough. Just use the OR constraint, as you saw
- in a previous example.
-
- (defrule cautious
- (light yellow|blinking-yellow)
- =>
- (printout "Be cautious" crlf))
-
- Suppose also that you want to identify the light color.
- The solution is to bind a variable to the color that is matched using the
- "&" and then print out the variable. This is where the "&" is useful,
- as shown below.
-
- (defrule cautious
- (light ?color&yellow|blinking-yellow)
- =>
- (printout "Be cautious" crlf))
-
- The variable ?color will be bound to whatever color is matched by the field
- yellow|blinking-yellow.
- The reason for not using a (bind) is because it is a RHS function and so
- cannot be used on the LHS. Likewise, you cannot use the logical
- constraints on the RHS.
- .PA
- Problem
-
-
- Write a program to simulate getting a car to run using the following
- information. The car has the following major components.
-
- engine
- spark plugs
- battery
- gas tank
- wheels
-
- For the car to move requires
-
- gas in the gas tank
- oil in the engine
- coolant in the engine
- electricity in the spark plugs
- inflated tires on the wheels
-
- If the gas, oil, coolant, and tires are not present, you must walk to a service
- station and buy them.
-
- If there is no electricity in the spark plugs, you must check the battery.
-
- If the battery is good, you must call a service station to tow the car to the
- service station.
-
- If a tire is not inflated, you must check to see if there is a leak.
-
- All four tires must be checked to see if they are inflated before the car can
- operate.
-
- If a tire has a leak, you must check the trunk to see if there is a jack and a
- spare tire.
-
- If there is no jack but there is a spare tire, you can borrow a jack from your
- neighbor.
-
- If there is a jack but no spare tire, you will borrow a tire from your spouse's
- car, then drive to a service station and buy a spare.
-
- If your car has been towed to a service station and you do not have towing
- insurance, you must pay $49 from cash, check, or charge sources.
-
- If you are at the service station and do not have a single source of payment
- to meet the cost of an item or towing, you must pay by combining
- sources.
-
- For expert advice on how to pay, write a advice rule which will let you pay by
- combining sources from cash, check, and charge. The following
- facts should be considered by the rule and then it should tell you what to do.
- Do not encode the numbers in the following facts in the rule.
- The rule should bind data from the facts to appropriate variables in the rule.
- You must always pay the towing charge in full and should buy as much gas and
- oil as you can pay for. You must have 1 container of coolant
- and at least 1 gallon of gas and 1 quart of oil for the car to run. You
- should try to buy as much as you can without overfilling.
-
- Facts
-
- You do not have towing insurance.
-
- The service station will not accept checks over $49
-
- You have $20 in cash
-
- You do not have a credit card
-
- You have $80 in your checking account
-
- The towing charge is $50
-
- Gas is $1.09 a gallon
-
- Oil is 1.56 a quart
-
- Capacity of gas tank is 15 gallons
-
- Capacity of engine for oil is 5 quarts
-
- A new battery is $42.95
-
- A new tire is $69.96
-
- A container of coolant is $2.98
-
- There is 0.5 gallons of gas
-
- There is no oil
-
- Two of your tires have leaks
-
- You have a spare tire and no jack
-
- You need 1 container of coolant
-
- The battery is bad
-
- You must not overfill the gas tank, engine oil, or coolant
-
- Make a (deffacts) of the appropriate facts and run. The program should tell
- you what to check and what to do for all the problems that occur.
- Depending on what you input when you're asked to check something, the program
- will take appropriate action.
-
-
-