This file is part of: AT&T Bell Laboratories and University of Pittsburgh CLASSIC Knowledge Representation System Tutorial Copyright AT&T and University of Pittsburgh 1994 ASG3.TXT PRELIMINARIES Open a new log file: >>> (dribble "your-file3.log") If you are continuing from asg2.txt in the same session, you may want to recover the state of the system (in case you erred at some point previously). To recover state type >>> (lload "Recover/after-wineries.lisp") Otherwise, if you are continuing from asg2.txt in the same session, you may want to skip down to the end of the review section. If you are starting this assignment in a new session, type: >>> (load "/Customize.lisp") >>> (lload "Recover/after-wineries.lisp") REVIEW OF asg1.txt and asg2.txt In the first module of this assignment we covered: 1. How to create "DISJOINT-PRIMITIVE" concepts. Using this construct we created the concepts WINE-PROPERTY, CONSUMABLE-THING, WINERY, and WINE-REGION. We also constructed the concepts EDIBLE-THING, POTABLE-LIQUID, WINE-COLOR, WINE-BODY, WINE-SUGAR, WINE-FLAVOR, WINE and MEAL-FOOD. 2. How to get more or less debugging information from Classic when concepts and individuals are defined. 3. Commands for inspecting and navigating the KB. 4. Definition of Roles and Attributes. 5. Creation of individuals and the effect of role restrictions on individuals. In the second module of this assignment we covered: 6. Adding concepts to the KB in such a way that existing concepts and instances get reclassified under them (we illustrated this with REGIONAL-WINERY and its children). 7. Use of the inverse of a role. You may want to review some of these ideas. Note that from this point in the tutorial, warnings will not be given before telling the user to do something that might cause an unexpected response. The user should now be familiar enough with Classic and its error messages to realize when an error message or unexpected response is being used to make a point. If Classic returns something unexpected, read it and read further in the tutorial to decipher whether it is making a point before trying to redo the command in order to get a "better" response. PRACTICE WITH A FEW DEFINED CONCEPTS ------------------------------------ We will now start developing the KB of wines. We'll begin with definitions of some generic wine subconcepts. You should be able to define them yourself from the following specifications: RED-WINE: Is a WINE with the color role filled by Red. ROSE-WINE: Is a WINE with the color role filled by Rose. WHITE-WINE: Is a WINE with the color role filled by White. WHITE-NON-SWEET-WINE: Is a WHITE-WINE with the sugar role restricted to be one of Dry or Off-Dry. FULL-BODIED-WINE: Is a WINE with Full body. DRY-WINE: Is a WINE with the sugar role filled by Dry. DRY-WHITE-WINE: Is a WHITE-WINE and a DRY-WINE. DRY-RED-WINE: Is a RED-WINE and a DRY-WINE. SWEET-WINE: Is a WINE with sugar role filled by Sweet. Try to define the concepts yourself first. If you can't or you want to check your definitions, look at "/Recover/after-generic-wines.lisp". Make sure these concepts are defined before going on. In the above definitions, you could have used "FILLS" or "ONE-OF". For instance, the alternative definitions are equivalent. >>> (cl-define-concept 'DELICATE-WINE1 '(AND WINE (FILLS flavor Delicate))) and >>> (cl-define-concept 'DELICATE-WINE2 '(AND WINE (ALL flavor (ONE-OF Delicate)) )) Enter the two definitions, and test for their equivalence. How can you tell that Classic identifies these two concepts? (Hint: Notice the object returned from the second definition. When Classic can prove two definitions equivalent, it doesn't create two concepts that are subsumed by each other. Instead, it adds the name of the second-defined concept to the list of non-primary names of the first-defined concept. Therefore, to test for equivalence between two concepts, you can either see if the both names are in the list of names for one of the concepts, or you can use the eql lisp function.) The equivalence of these two definitions depends on the fact that flavor is an attribute, and that WINEs were required by definition to have at least one flavor. To illustrate the difference between such definitions in general, recall the definition of MEAL-FOOD. (cl-define-concept 'MEAL-FOOD '(AND EDIBLE-THING (AT-LEAST 1 appropriate-drink) (ALL appropriate-drink WINE) ) (You do not need to enter this definition!) Now, suppose that we define FOOD-GOOD-WITH-FORMAN-CHARDONNAY to be any MEAL-FOOD whose appropriate-drink role is filled with Forman-Chardonnay. (Enter the definition.) And let's define FOOD-GOOD-ONLY-WITH-FORMAN-CHARDONNAY to be any MEAL-FOOD all of whose appropriate-drinks are ONE-OF Forman-Chardonnay. (Enter the definition.) Would you expect either of these concepts to be classified under the other? Does Classic give the answer that you expect? Comment out your response. If Classic does not deduce that one of these concepts subsumes the other, it should be possible to create an individual that is subsumed by the first concept but not the second. Create such individuals now, and test them. (For instance, if Classic does not classify FOOD-GOOD-ONLY-WITH-FORMAN-CHARDONNAY under FOOD-GOOD-WITH-FORMAN-CHARDONNAY, create a specific individual Food1 that has FOOD-GOOD-WITH-FORMAN-CHARDONNAY as an ancestor, but not FOOD-GOOD-ONLY-WITH-FORMAN-CHARDONNAY.) USING RULES IN CLASSIC ---------------------- In this section we will learn to use rules in Classic and at the same time fill out the rest of the KB under WINE. USING RULES TO ENHANCE CONCEPTS In this section we will consider the use of rules in concept definitions. Consider the following definition of the concept CHARDONNAY: >>> (cl-define-concept 'CHARDONNAY '(AND wine (FILLS grape Chardonnay) )) This says that by definition, a CHARDONNAY is a wine with its grape role filled by Chardonnay. Since our simple definition of grape requires it to be an attribute, this means that a CHARDONNAY wine will have Chardonnay as its only grape. But there's a lot more we know about Chardonnay wines, e.g., they are white, they usually have full or medium body, and they have strong or moderate flavor. However, these things are not part of the definition of CHARDONNAY, they are incidental properties that are typical of Chardonnay wines. To specify such properties, we use rules like the following: >>> (cl-add-rule 'chardonnay-color @c{chardonnay} '(fills color white)) >>> (cl-add-rule 'chardonnay-body @c{chardonnay} '(all body (one-of full medium))) >>> (cl-add-rule 'chardonnay-flavor @c{chardonnay} '(all flavor (one-of strong moderate))) Enter the concept definition of Chardonnay and then enter the rules. (The rules use the Chardonnay concept). These rules say that any individual that gets classified as a CHARDONNAY will also be given certain constraints. Rules can be added incrementally at any point in building a knowledge base and will affect both existing individuals and individuals created later. You may have noticed that when we defined WINE, we were not able to place an appropriately specific restriction on the grape role. As a reminder, we repeat the role information from the definition of WINE. Role Restrictions: Color![1 ; 1] => @c{WINE-COLOR} Body![1 ; 1] => @c{WINE-BODY} Flavor![1 ; 1] => @c{WINE-FLAVOR} Sugar![1 ; 1] => @c{WINE-SUGAR} Grape![1 ; 1] => @c{EDIBLE-THING} You would have expected a restriction to GRAPE in the Grape role, rather than to the less specific EDIBLE-THING. We had to be content with the definition that we used because Classic will not tolerate circularities in definitions. GRAPE is defined in our KB in a way that classifies it under MEAL-FOOD; browse in the KB to determine the chain of parent concepts that lead from GRAPE to MEAL-FOOD. But in our KB, MEAL-FOOD is a defined concept, and part of the definition is a restriction of the appropriate-drink role to WINE! It was to avoid this circle that we used EDIBLE-THING rather than GRAPE. We can repair this by adding a rule restricting the fillers of the grape role in WINE to GRAPE. Write this rule now. We also expect each WINE to have a maker (which is a WINERY), and a region (which is a WINE-REGION). In this domain, we can expect each WINE to have exactly one region, and exactly one maker. So we can treat these roles as attributes. (Remember that :attribute and :inverse are keywords for the function you will use to add these roles). Use that function to add them now, and write rules that attach them to WINE. Now, let's return to CHARDONNAY. Recall that we added rules to the definition of this wine, providing information about color, body, and flavor. Here is what the rule information looks like if you inspect the concept CHARDONNAY. >>> (cl-print-concept @C{CHARDONNAY}) @c{CHARDONNAY} -> Derived Information: Primitive ancestors: (@c{POTABLE-LIQUID} @c{CONSUMABLE-THING} @c{CLASSIC-THING}) Parents: (@c{WINE}) Ancestors: (@c{THING} @c{CLASSIC-THING} @c{CONSUMABLE-THING} @c{POTABLE-LIQUID}) Role Restrictions: Color![1 ; 1] => @c{WINE-COLOR} Body![1 ; 1] => @c{WINE-BODY} Flavor![1 ; 1] => @c{WINE-FLAVOR} Sugar![1 ; 1] => @c{WINE-SUGAR} Grape![1 ; 1] -> (@i{CHARDONNAY}) => @c{EDIBLE-THING} Rules: 1. @rule{WINE-GRAPE} -> Antecedent: @c{WINE} Consequent: Role Restrictions: Grape! => @c{GRAPE} 2. @rule{WINE-MAKER} -> Antecedent: @c{WINE} Consequent: Role Restrictions: Maker![1 ; 1] => @c{WINERY} 3. @rule{WINE-REGION} -> Antecedent: @c{WINE} Consequent: Role Restrictions: Region![1 ; 1] => @c{WINE-REGION} @c{CHARDONNAY} There is not as much information attached to the concept as you might expect, because rules are only used in Classic to obtain information about individuals. We can use this fact to find out what Classic knows about the concept, by creating a temporary "generic individual". What makes this individual a generic Chardonnay is the fact that we will only attach information to it that is already included in the CHARDONNAY concept. Let's create the individual Generic-Chardonnay, and see what happens. (You can enter the following command line if you like, to see that Classic in fact behaves as reported here. Or you can simply read the following few lines.) >>> (cl-create-ind 'Generic-Chardonnay 'CHARDONNAY) @i{GENERIC-CHARDONNAY} >>> (cl-print-object @i{GENERIC-CHARDONNAY}) @i{GENERIC-CHARDONNAY} -> Derived Information: Primitive ancestors: (@c{POTABLE-LIQUID} @c{CONSUMABLE-THING} @c{CLASSIC-THING}) Parents: (@c{WHITE-WINE} @c{CHARDONNAY}) Ancestors: (@c{THING} @c{CLASSIC-THING} @c{CONSUMABLE-THING} @c{POTABLE-LIQUID} @c{WINE}) Role Fillers and Restrictions: Region![1 ; 1] => @c{WINE-REGION} Maker![1 ; 1] => @c{WINERY} Grape![1 ; 1] -> (@i{CHARDONNAY}) => @c{GRAPE} Flavor![1 ; 1] => Primitive ancestors: (@c{WINE-PROPERTY} @c{CLASSIC-THING}) One-of Restr: (@i{MODERATE} @i{STRONG}) Body![1 ; 1] => Primitive ancestors: (@c{WINE-PROPERTY} @c{CLASSIC-THING}) One-of Restr: (@i{MEDIUM} @i{FULL}) Color![1 ; 1] -> (@i{WHITE}) => @c{WINE-COLOR} Sugar![1 ; 1] => @c{WINE-SUGAR} @i{GENERIC-CHARDONNAY} There are several points to be made here: There is some fairly sophisticated classificational reasoning going on here. The role color has been filled with White by a rule. Thus, because Generic-Chardonnay has color White, the Classic classifier can determine that Generic-Chardonnay is also a WHITE-WINE. We can also see that the body and flavor roles have not been filled, since the restriction to one of two fillers for body and flavor does not allow Classic to infer a single filler: >>> (cl-fillers @i{Generic-Chardonnay} @r{flavor}) NIL >>> (cl-fillers @i{Generic-Chardonnay} @r{body}) NIL Instead, restrictions have been added to Generic-Chardonnay by the rules attached to the CHARDONNAY and the WINE concept: >>> (cl-print-ind @i{Generic-Chardonnay}) @I{GENERIC-CHARDONNAY} -> ... Role Fillers and Restrictions: Region![1 ; 1] => @c{WINE-REGION} Maker![1 ; 1] => @c{WINERY} Grape![1 ; 1] -> (@i{CHARDONNAY}) => @c{GRAPE} Flavor![1 ; 1] => Primitive ancestors: (@c{WINE-PROPERTY} @c{CLASSIC-THING}) One-of Restr: (@i{MODERATE} @i{STRONG}) Body![1 ; 1] => Primitive ancestors: (@c{WINE-PROPERTY} @c{CLASSIC-THING}) One-of Restr: (@i{MEDIUM} @i{FULL}) Color![1 ; 1] -> (@i{WHITE}) => @c{WINE-COLOR} Sugar![1 ; 1] => @c{WINE-SUGAR} @i{GENERIC-CHARDONNAY} Be sure that you understand the sources of the information that are reported in the above printout; what definitions and rules are used? To illustrate the incremental addition of information to individuals, let's create another individual, My-Chardonnay. My-Chardonnay will begin life as a generic CHARDONNAY, but we will add information to it using "IND-ADD", which acts somewhat like a rule, but is restricted to a particular individual. At this point, you should create My-Chardonnay and print information about it. Classic should report that My-Chardonnay looks just like Generic-Chardonnay. With My-Chardonnay in the KB, first try to add information that conflicts with the rules associated with CHARDONNAY. Try the following: the attempt should create an error. Add the fact that My-Chardonnay's flavor is Delicate. Now, try the following. (Use one Classic command to do this, rather than two.) This time, the attempt should work. Add the fact that My-Chardonnay's flavor is Strong, and its body is Medium. Here is what you should get at this point if you ask about My-Chardonnay. >>> (cl-print-ind @My-Chardonnay) @i{MY-CHARDONNAY} -> Derived Information: Primitive ancestors: (@c{POTABLE-LIQUID} @c{CONSUMABLE-THING} @c{CLASSIC-THING}) Parents: (@c{WHITE-WINE} @c{CHARDONNAY}) Ancestors: (@c{THING} @c{CLASSIC-THING} @c{CONSUMABLE-THING} @c{POTABLE-LIQUID} @c{WINE}) Role Fillers and Restrictions: Region![1 ; 1] => @c{WINE-REGION} Maker![1 ; 1] => @c{WINERY} Grape![1 ; 1] -> (@i{CHARDONNAY}) => @c{GRAPE} Flavor![1 ; 1] -> (@i{STRONG}) => Primitive ancestors: (@c{WINE-PROPERTY} @c{CLASSIC-THING}) One-of Restr: (@i{MODERATE} @i{STRONG}) Body![1 ; 1] -> (@i{MEDIUM}) => Primitive ancestors: (@c{WINE-PROPERTY} @c{CLASSIC-THING}) One-of Restr: (@i{MEDIUM} @i{FULL}) Color![1 ; 1] -> (@i{WHITE}) => @c{WINE-COLOR} Sugar![1 ; 1] => @c{WINE-SUGAR} @i{MY-CHARDONNAY} It would be nice to have a function that takes an instance, e.g, @i{MY-CHARDONNAY} as an argument, and returns a list of the roles and their fillers, e.g., a function that has the following behavior: > (find-role-fillers @i{MY-CHARDONNAY}) ((@r{GRAPE} @i{CHARDONNAY}) (@r{REGION}) (@r{SUGAR}) (@r{COLOR} @i{WHITE}) (@r{BODY} @i{MEDIUM}) (@r{FLAVOR} @i{STRONG}) (@r{MAKER})) Try writing such a function using existing Classic functions. If you use the Common LISP macro LOOP, this function takes 3 lines of code (and that's putting the defun on a separate line!) The trick is to find the functions that Classic already provides that makes writing this function trivial. Before you go on, type: >>> (lload "Recover/after-wine-varieties.lisp") You may get an error saying that CHARDONNAY has already been defined. Ignore it. Because they add information to an individual classified under the concept that is the antecedent of the rule, rules may also cause further classification to occur. Consider the following individual. (Type it in). >>> (cl-create-ind 'Chateau-lafite-rothschild-pauillac '(AND PAUILLAC (FILLS maker Chateau-lafite-rothschild))) Then look at what its ancestors are. It was only asserted to be a PAUILLAC, but a PAUILLAC is a MEDOC and MEDOC has rules that set sugar to Dry, and color to Red. Therefore, Chateau-Lafite-Rothschild can be inferred to be a DRY-RED-WINE and a CABERNET-SAUVIGNON-WINE. WHY ARE RULES BEING USED? There are several reasons for using rules, but the reason they are being used here, in the definition of the wine varieties, is probably the most important one from a conceptual point of view. Basically, rules are used to add to an individual information that is not definitional, i.e., you do not want to force an individual to have that information associated with it before you classify it as an instance of the concept. In the case of CHARDONNAY, above, the concept definition is saying that the color, body, and flavor information is not definitional for concept CHARDONNAY, although an individual that is classified as a CHARDONNAY will have these characteristics. The definitional characteristic of CHARDONNAY is the type of grape it is made from. As another more familiar example, consider a concept PERSON. We know that PERSONs have a social security number, but it should not be necessary for a person to have a SSN in order to be classified as a PERSON. Instead we would want the system to infer that it has a SSN and that, even if you didn't know what it was, it would have to have 9 digits. So you might add a rule to that effect. INFORMATION THAT CAN BE ADDED WITH RULES Rules, we said, are commonly used to add non-definitional information to instances of a concept. This information can be restrictions, fillers, or parents. 1. ADDING RESTRICTIONS. We have already seen, with CHARDONNAY and My-Chardonnay, an example of adding restrictions. Recall that body and flavor got their restrictions from rules. 2. ADDING FILLERS. Here is an example of adding fillers explicitly (grape is filled by inheritance). The file /Helper/wine-varieties defined CHENIN-BLANC as follows: (cl-define-concept 'CHENIN-BLANC '(AND WINE (fills grape CHENIN-BLANC))) (cl-add-rule 'chenin-blanc-color @c{CHENIN-BLANC} '(fills color White)) (cl-add-rule 'chenin-blanc-body @c{CHENIN-BLANC} '(all body (one-of Full Medium))) (cl-add-rule 'chenin-blanc-flavor @c{CHENIN-BLANC} '(fills flavor Moderate)) (cl-add-rule 'chenin-blanc-sugar @c{CHENIN-BLANC} '(all sugar (one-of Dry Off-dry))) Create an individual called Ventana-Chenin-Blanc that is a CHENIN-BLANC and has maker Ventana. Then print the object and verify that the roles color and flavor now each have a filler. 3. ADDING PARENTS. Here is an example of explicitly classifying an individual under a different concept. Type the following definitions. (cl-define-concept 'SPECIAL-RED-BORDEAUX '(AND BORDEAUX-WINE RED-WINE)) (cl-add-rule 'special-red-bordeaux-type @c{SPECIAL-RED-BORDEAUX} 'CABERNET-SAUVIGNON-WINE) Any instance of SPECIAL-RED-BORDEAUX will become a CABERNET-SAUVIGNON-WINE as well. Create an individual called My-Red-Bordeaux and define it to be a BORDEAUX-WINE and a RED-WINE (these concepts were already defined). Verify that its ancestors are: 1. A RED-BORDEAUX (because of the definition of RED-BORDEAUX) 2. A CABERNET-SAUVIGNON-WINE (because of the rule above) 3. A DRY-RED-WINE (because CABERNET-SAUVIGNON-WINEs are restricted to be dry) ADDING AND REMOVING RULES Rules do not need to be specified when a concept is defined. They can be added later as well as removed. Let's modify the information associated with the instances of RED-BORDEAUX (see above) by removing the special-red-bordeaux-type rule, and then let's add it back in. To remove the rule, type: >>> (cl-remove-rule (cl-named-rule 'special-red-bordeaux-type)) This will take a little time because it has to remove the rule as well as retract any inferences made when the rule fired on individuals. Check that the wine we created, My-Red-Bordeaux, is now no longer classified as either a CABERNET-SAUVIGNON or a DRY-RED-WINE. If we add the rule back in: >>> (cl-add-rule 'special-red-bordeaux-type @c{SPECIAL-RED-BORDEAUX} 'CABERNET-SAUVIGNON-WINE) the rule-derived ancestry for My-Red-Bordeaux is reestablished. FILTERS ON RULES: A rule may optionally contain a filter which is a concept description that must be satisfied before the rule can fire. By using a filter, we can avoid creating an unnecessary named concept whose only purpose is to be the antecedent of a rule. (QUESTION: Why is it a good idea not to create named concepts that are unnecessary? Type your answer into the lisp session in lines that begin with the comment symbol ";" so that your answer will appear in your dribble file.) First define a primitive concept called RICH-FAVORITE-WINE that is a WINE. Now define a rule called RICH-FAV that infers that a WINE is Rich's favorite wine if its color is RED and the wine is made only of the grape Cabernet-sauvignon. Create an individual, call it Good-wine, that will cause the rule RICH-FAV to fire and classify Good-wine under RICH-FAVORITE-WINE. Show that this classification happens. There are other types of rules in CLASSIC. Make sure you read the manual and understand these. Type: (dribble) to close your log file now. --------------------------------------------------------------------------- END OF asg3.txt If you are going on open the file "/asg4.txt"