|
|
1.1 ! root 1: .so /usr/lib/vlpmacs ! 2: .ND ! 3: .ds CH ! 4: .ds CF - % - ! 5: .po 1.00i ! 6: .nr LL 6.25i ! 7: .RP ! 8: .TL ! 9: .LG ! 10: The Implementation of PEARL ! 11: .SM ! 12: .sp 1 ! 13: A Package for Efficient Access to ! 14: Representations in Lisp* ! 15: .FS ! 16: * This research was sponsored in part by the Office of Naval Research ! 17: under contract N00014-80-C-0732 and the National Science Foundation ! 18: under grant MCS79-06543. ! 19: .FE ! 20: .AU ! 21: Joseph Faletti ! 22: Robert Wilensky ! 23: .AI ! 24: Computer Science Division ! 25: Department of EECS ! 26: University of California, Berkeley ! 27: Berkeley, California 94720 ! 28: .sp 1 ! 29: March 1982 ! 30: .AB ! 31: PEARL is an AI language developed with space and ! 32: time efficiencies in mind. ! 33: In addition to providing the usual facilities such as ! 34: slot-filler objects, demons and associative data bases, ! 35: PEARL introduces stronger typing on slots, ! 36: user-assisted hashing mechanisms, and a forest of data bases. ! 37: The resulting product is a simple but powerful and efficient ! 38: tool for AI research. ! 39: .AE ! 40: .NH ! 41: Introduction ! 42: .sp 3 ! 43: .PP ! 44: We have developed an AI language called PEARL (Package for Efficient ! 45: Access to Representations in Lisp). ! 46: Unlike the recent tendency toward ! 47: elaborate representation languages such as KRL [1] ! 48: or language generators such as RRL [5], PEARL is ! 49: a more modest system that combines a number of useful ! 50: AI techniques into a very efficient package. ! 51: PEARL provides the user with a set of operators for defining, creating, ! 52: and manipulating slot-filler objects, as well as placing them into ! 53: associative data bases, upon which further operations may be performed. ! 54: Besides the usual goal of providing the user with a more meaningful ! 55: interface than is available via Lisp, PEARL has the following salient ! 56: characteristics: ! 57: .IP 1) ! 58: PEARL combines some features of predicate calculus-like data bases with ! 59: those of frame-based systems like FRL [9]. ! 60: .IP 2) ! 61: PEARL introduces typing to user-defined knowledge structures. ! 62: .IP 3) ! 63: PEARL allows the user to manipulate a forest of associative ! 64: data bases implemented as hash tables. ! 65: .IP 4) ! 66: Fetches from the data base return streams of answers. ! 67: Retrieval is based on pattern matching. ! 68: .IP 5) ! 69: PEARL is very efficient. ! 70: PEARL uses its own internal representation ! 71: for knowledge structures for both economy of storage and speed. ! 72: A great deal of effort has gone into exploiting type information ! 73: not available in most AI languages to eliminate searching inefficiencies. ! 74: In addition, the user may easily specify, as part of a knowledge ! 75: structure definition, a great deal of information about how ! 76: objects should be indexed for efficient retrieval. ! 77: Thus PEARL provides much of the power ! 78: of expression of other AI languages without the usual overhead. ! 79: .LP ! 80: Perhaps most significantly, PEARL is actually being used in the ! 81: construction of several AI systems. ! 82: In particular, the latest version of PAM [12], ! 83: a story understanding program, has been re-programmed in PEARL. ! 84: PANDORA [13], a planning program now under development at Berkeley, ! 85: is also written in PEARL. ! 86: Our experience has led us to conclude that PEARL ! 87: is an effective AI tool for the creation of efficient AI programs. ! 88: .sp 3 ! 89: .PP ! 90: The following is a quick overview of the paper: ! 91: First we present an overview of PEARL by discussing a sample session ! 92: which demonstrates the primary functions provided. ! 93: Next we present some measurements as evidence that PEARL is ! 94: indeed efficient. ! 95: The bulk of the paper then describes the details of each of PEARL's ! 96: main functions -- creating structures, the form of the data bases, ! 97: indicating indexing methods, fetching from the data bases, predicates ! 98: and matching, matching variables, and demons. ! 99: This is followed by descriptions of the various implementations of ! 100: PEARL and their relative speeds plus evidence that PEARL's hashing ! 101: mechanism does in fact speed up fetching. ! 102: Finally, we compare PEARL to its nearest cousins, FRL and KRL. ! 103: .NH ! 104: An Overview and Sample Application Of PEARL ! 105: .sp 3 ! 106: .PP ! 107: In the section we give an overview of PEARL by presenting an ! 108: extended example of PEARL's use. ! 109: The example we will use to demonstrate the various features of ! 110: PEARL before going into each in more detail is a \fIvery simple\fR ! 111: inference mechanism based on forward and backward inferences rules. ! 112: In order to explain and motivate the various pieces of PEARL (and ! 113: Lisp) code, we present them in the order that one would most likely ! 114: design them, rather than the order that they must be entered ! 115: into PEARL. Afterwards, they would have to be moved around so ! 116: that things are defined before being referenced. ! 117: .sp 3 ! 118: .PP ! 119: To implement the inference mechanism, we will want to ensure that ! 120: we perform forward inferences whenever we insert a concept into ! 121: the data base and backward inference whenever we fetch a concept ! 122: from the data base. The easiest way to accomplish this is to ! 123: create two demons, one for forward inference and one for backward ! 124: inference which will be run when insert and fetching respectively ! 125: happens. These will need to be attached to all concepts which we ! 126: want to make inferences from, so we need a \fIstructure\fR (PEARL's ! 127: name for a slot/filler object) which we will call \fIConcept\fR. ! 128: It will have no slots but will be used as the root of our ! 129: conceptual hierarchy so that all concepts can inherit the ! 130: inference demons from it. ! 131: (We will add these later when we know what their names are). ! 132: We do this in PEARL by declaring a \fIbase\fR structure called \fIConcept\fR: ! 133: .DS ! 134: (create base Concept) ! 135: .DE ! 136: .sp 3 ! 137: .PP ! 138: We will then want to describe some of the concepts that we ! 139: wish to make inferences about. ! 140: For the purposes of this example, we will present only enough ! 141: information to use backward inference to determine that Samuel is ! 142: probably poor from the fact that he is a professor. ! 143: So we will want structures which describe a person, a professor, ! 144: a salary level, and being poor. ! 145: \fIPerson\fR is an expanded \fIConcept\fR; ! 146: that is, it should inherit everything not otherwise specified from ! 147: the structure \fIConcept\fR. ! 148: It will have one slot (for our current purposes) containing the ! 149: person's name which we will represent as a \fIsymbol\fR which is ! 150: used in PEARL for creating literals (that it, something with no ! 151: conceptual content): ! 152: .DS ! 153: .Ls ! 154: (create \kAexpanded Concept Person ! 155: \h'|\nAu'(* Name symbol)) ! 156: .Le ! 157: .DE ! 158: .LP ! 159: Included in our definition is a special hashing mark (*) on the ! 160: Name slot which says that the value in this slot should be ! 161: helpful in indexing \fIPerson\fR structures. ! 162: This is true because we are likely to be asking questions of the ! 163: data base like "Is Samuel the name of a person?". ! 164: For example, suppose we have declared the symbol Samuel: ! 165: .DS ! 166: (symbol Samuel) ! 167: .DE ! 168: .LP ! 169: and asserted into the data base the fact that there is a person named ! 170: \fISamuel\fR by creating an individual instance of a \fIPerson\fR ! 171: with the \fIName\fR slot filled with the symbol \fISamuel\fR and ! 172: inserting it into the data base: ! 173: .DS ! 174: .Ls ! 175: (insertdb (create \kAindividual Person Sam ! 176: \h'|\nAu'(Name Samuel))) ! 177: .Le ! 178: .DE ! 179: .LP ! 180: (As a side effect of the above, the individual structure instance ! 181: \fI(Person (Name Samuel))\fR is stored in the Lisp atom \fISam\fR ! 182: for future use.) ! 183: The function \fIinsertdb\fR uses the hashing information we gave ! 184: for \fIPerson\fR to insert this structure in the data base in ! 185: two places: under the fact that it is a \fIPerson\fR which is ! 186: automatic for all structures and under the combination of ! 187: \fIPerson\fR and \fISamuel\fR because we bothered to provide ! 188: the extra information in our definition of \fIPerson\fR. ! 189: .sp 3 ! 190: .PP ! 191: Now we can "phrase" the question "Is Samuel the name ! 192: of a person?" as: ! 193: .DS ! 194: .Ls ! 195: (setq Stream (fetch (create \kAindividual Person ! 196: \h'|\nAu'(Name Samuel))) ! 197: .Le ! 198: .DE ! 199: .LP ! 200: that is, by creating an individual \fIPerson\fR with name \fISamuel\fR, ! 201: and fetching it from the data base. ! 202: This returns a hash bucket from the data base which is chosen ! 203: based on two parts of our pattern: the fact that it is a ! 204: \fIPerson\fR structure (because this is always available) ! 205: plus the value in the Name slot (because we labelled this slot ! 206: in our definition of \fIPerson\fR. ! 207: Given this stream (virtual list) of possible matches, we ask ! 208: whether there is in fact something there which matches our pattern: ! 209: .DS ! 210: (setq Result (nextitem Stream)) ! 211: .DE ! 212: .LP ! 213: If Result is \fInil\fR then the fact that Sam is a Person is not ! 214: in the data base. ! 215: If it is, then Result will contain the structure in the data base. ! 216: .sp 3 ! 217: .PP ! 218: Similarly, we declare the structure \fIProfessor\fR, ! 219: a predicate about a (structure of type) \fIPerson\fR and ! 220: assert that Sam is a \fIProfessor\fR using the structure ! 221: value we stored in \fISam\fR before: ! 222: .DS ! 223: .Ls ! 224: (create \kAexpanded Concept Professor ! 225: \h'|\nAu'(* > Person Person)) ! 226: (insertdb (create \kAindividual Professor ! 227: \h'|\nAu'(Person Sam))) ! 228: .Le ! 229: .DE ! 230: .sp 3 ! 231: .PP ! 232: In choosing a way to index this structure, we consider the fact ! 233: that Person slot of \fIProfessor\fR will always contain a ! 234: \fIPerson\fR structure and thus the combination of \fIProfessor\fR ! 235: and \fIPerson\fR will not help to spread these out in our data base. ! 236: However, the value of the first marked slot \fIName\fR of Person will ! 237: contain widely varying information so the combination of ! 238: \fIProfessor\fR and this value will work well. ! 239: The hashing mark ">" instructs PEARL to do precisely this. ! 240: We also define \fISalary\fR, a relation between an \fIEmployee\fR ! 241: and a salary level: ! 242: .DS ! 243: .Ls ! 244: (create \kBexpanded Concept Salary ! 245: \h'|\nBu'\kA(* > Employee Person) ! 246: \h'|\nAu'( Level symbol)) ! 247: .Le ! 248: .DE ! 249: .LP ! 250: Here the first slot is starred because we are likely to ask for ! 251: the salary of Sam. ! 252: If we were also likely to ask for all people with Low salaries, ! 253: then we would star the second slot also. ! 254: Finally, we define \fIPoor\fR, a predicate about a \fIPerson\fR: ! 255: .DS ! 256: .Ls ! 257: (create \kAexpanded Concept Poor ! 258: \h'|\nAu'(* > Person Person)) ! 259: .Le ! 260: .DE ! 261: .LP ! 262: Having defined the types of objects we know about and the few ! 263: actual facts we know, we are ready to describe the inference ! 264: rules. ! 265: Forward rules say that if the value in the Fact slot is true then ! 266: the value in the Implies slot is true also. ! 267: We are likely to fetch them using Fact as a key, so we mark that ! 268: slot as useful in hashing: ! 269: .DS ! 270: .Ls ! 271: (create \kBbase ForwardRule ! 272: \h'|\nBu'\kA(* Fact Concept) ! 273: \h'|\nAu'( Implies Concept)) ! 274: .Le ! 275: .DE ! 276: .LP ! 277: Backward rules say that if you want to know if the value in the Need ! 278: slot is true then check to see if the value in the LookFor slot is true: ! 279: .DS ! 280: .Ls ! 281: (create \kBbase BackwardRule ! 282: \h'|\nBu'\kA(* Need Concept) ! 283: \h'|\nAu'( LookFor Concept)) ! 284: .Le ! 285: .DE ! 286: .LP ! 287: Finally, we need to add some rules to our data base. ! 288: Since we are likely to know a lot of inference rules and to want ! 289: to access them often, it would help to keep them in a different ! 290: data base separate from other facts to speed up access. ! 291: So we build a special data base just for inference rules: ! 292: .DS ! 293: (builddb *Rules*) ! 294: .DE ! 295: .LP ! 296: Then we insert some rules into it: ! 297: .DS ! 298: (symbol Low) ! 299: .DE ! 300: .DS ! 301: .Ls ! 302: \fI; If you want to know if someone is poor, check for a low pay level.\fP ! 303: (insertdb \kA(create \kBindividual BackwardRule ! 304: \h'|\nBu'\kC(Need (Poor (Person ?Person))) ! 305: \h'|\nCu'(LookFor (Salary \kB(Employee ?Person) ! 306: \h'|\nBu'(Level Low)))) ! 307: \h'|\nAu'*Rules*) ! 308: .Le ! 309: .DE ! 310: .DS ! 311: .Ls ! 312: \fI; If you want to know if someone's pay level is low, check to\fP ! 313: \fI; see if they are a professor.\fP ! 314: (insertdb \kA(create \kDindividual BackwardRule ! 315: \h'|\nDu'\kB(Need (Salary \kC(Employee ?Person) ! 316: \h'|\nCu'(Level Low))) ! 317: \h'|\nBu'(LookFor (Professor (Person ?Person)))) ! 318: \h'|\nAu'*Rules*) ! 319: .Le ! 320: .DE ! 321: .LP ! 322: Note in our rules that we use the pattern matching variable \fI?Person\fR. ! 323: In the first rule this ties together the person who is poor with the ! 324: person whose is paid at a low level. ! 325: In the second rule it ties together the person with low pay ! 326: to the professor. ! 327: Although these two rules have variables with the same name, no ! 328: naming conflict arises because most variables in PEARL are local ! 329: to the structure they are used in. ! 330: .sp 3 ! 331: .PP ! 332: Next we are in a position to say how to make forward inferences: ! 333: .DS ! 334: .Ls ! 335: \fI; MakeForwardInference is a demon, triggered by insertions into the\fP ! 336: \fI; data base, which fetches forward inference rules predicated upon\fP ! 337: \fI; the Fact being inserted and inserts the implications from the\fP ! 338: \fI; rule into the data base.\fP ! 339: (de \kDMakeForwardInference (Fact) ! 340: \h'|\nDu'(prog \kC(Rules Rule) ! 341: \h'|\nCu'\kB(setq \kDRules ! 342: \h'|\nDu'(fetch \kA(create \kCpattern ForwardRule ! 343: \h'|\nCu'(Fact Fact)) ! 344: \h'|\nAu'*Rules*)) ! 345: \h'|\nBu'(while \kA(setq Rule (nextitem Rules)) ! 346: \h'|\nAu'(insertdb (path get Rule 'Implies))))) ! 347: .Le ! 348: .DE ! 349: .LP ! 350: This says to fetch all forward inference rules with the new fact ! 351: in the Fact slot and assert each of their associated Implies slots. ! 352: .sp 3 ! 353: .PP ! 354: Making backward inferences is similar but a bit more complex ! 355: because we want it to stop right away if it succeeds: ! 356: .DS ! 357: .Ls ! 358: \fI; MakeBackwardInference is a demon, triggered by fetches from the\fP ! 359: \fI; data base which fetches backward inference rules whose Need\fP ! 360: \fI; slot contains the Fact being inserted and fetches the value\fP ! 361: \fI; of the rule's LookFor slot from the data base until one succeeds.\fP ! 362: (de \kBMakeBackwardInference (Fact) ! 363: \h'|\nBu'(prog \kA(Rules Rule Found Try) ! 364: \h'|\nAu'\kC(setq Rules (fetch \kD(create \kBpattern BackwardRule ! 365: \h'|\nBu'(Need Fact)) ! 366: \h'|\nDu'*Rules*)) ! 367: \h'|\nCu'\kD(setq Found nil) ! 368: \h'|\nDu'\kA(while \kB(and \kC(not Found) ! 369: \h'|\nCu'(setq Rule (nextitem Rules))) ! 370: \h'|\nBu'\kC\fI; Get the LookFor slot's value.\fP ! 371: \h'|\nCu'\kB(setq Try (path get Rule 'LookFor)) ! 372: \h'|\nBu'(cond (\kC(nextitem (fetch Try)) ! 373: \h'|\nCu'\kB(insertdb Fact) ! 374: \h'|\nBu'(setq Found t)))) ! 375: \h'|\nAu'(return Found))) ! 376: .Le ! 377: .DE ! 378: .LP ! 379: Finally, we can finish our description of \fIConcept\fR by saying ! 380: that all concepts inserted into the data base should run the demon ! 381: MakeForwardInference after the insertion has been performed (">insertdb"). ! 382: All concepts fetched from the data base should run MakeBackwardInference ! 383: \fIbefore\fR the fetch has been performed ("<fetch"): ! 384: .DS ! 385: .Ls ! 386: (create \kBbase Concept ! 387: \h'|\nBu'(if \kA>insertdb MakeForwardInference ! 388: \h'|\nAu'<fetch MakeBackwardInference)) ! 389: .Le ! 390: .DE ! 391: .LP ! 392: Now we "phrase" our question "Is Sam poor?" as a pattern: ! 393: .DS ! 394: .Ls ! 395: (create \kApattern Poor NeededFact ! 396: \h'|\nAu'(Person Sam)) ! 397: .Le ! 398: .DE ! 399: .LP ! 400: This fact is not in the data base. ! 401: However, upon fetching it: ! 402: .DS ! 403: (nextitem (fetch NeededFact)) ! 404: .DE ! 405: .LP ! 406: Our two backward inference rules will be used by our backward ! 407: inference demon and the desired fact will have been inserted into ! 408: the data base before the fetch does its job. ! 409: .sp 3 ! 410: .PP ! 411: This example demonstrates a good deal of what PEARL can do and ! 412: gives the flavor of its use. ! 413: After presenting some measurements of its speed, we will discuss ! 414: each of its features in more detail and describe their ! 415: implementations. ! 416: .sp 3 ! 417: .PP ! 418: The above example was described as a user would design and enter ! 419: code into a file to be read into PEARL. ! 420: This is the normal mode for experienced users of PEARL, just as it ! 421: is for Lisp programmers. ! 422: PEARL can also be used interactively since it is ! 423: built on top of Lisp. ! 424: However, PEARL constructs objects which Lisp does not know how ! 425: to print intelligibly. ! 426: To remedy this, the read-eval-print loop of Lisp has been modified ! 427: to deal with PEARL objects and uses PEARL's print function to ! 428: print a readable representation of them. ! 429: To help demonstrate what it is like to use PEARL interactively, ! 430: the examples in later sections use italics to indicate those things ! 431: typed by PEARL during an interactive session and bold face to ! 432: indicate those things typed by the user. ! 433: To remind the users that they are using PEARL ! 434: rather than Lisp, the prompt has been changed to \fIpearl>\fR. ! 435: .NH ! 436: How Fast Is PEARL? ! 437: .sp 3 ! 438: .PP ! 439: PEARL achieves its space efficiency and some of its time efficiency ! 440: by requesting a block of memory from Lisp for each structure ! 441: instance or definition. ! 442: The contents or defining information are then packed within ! 443: this block. ! 444: Since much of the defining information is Boolean, ! 445: this provides substantial savings in space for definitions. ! 446: Data bases are managed similarly. ! 447: .sp 3 ! 448: .PP ! 449: As a rough measure of PEARL's execution speed on the PDP-10, ! 450: we created a test data base of 4000 structures, in which the ! 451: average unsuccessful query took 0.0042 CPU seconds (237 per ! 452: second) and the average successful query took 0.0073 CPU seconds ! 453: (136 per second). ! 454: Note that PEARL's hashing mechanism results in particularly fast ! 455: determination of failure. ! 456: As another measure of PEARL's execution speed, we ! 457: compared the original implementation of PAM [12] written purely in Lisp ! 458: (with no special consideration for efficiency) ! 459: with the current implementation which uses PEARL. ! 460: The average time required by the original to process a single ! 461: sentence in a 5-sentence story was 5.6 CPU seconds. ! 462: The new version, which builds a more complete representation of ! 463: the overall structure of the story and uses a significantly ! 464: larger collection of knowledge, requires an average of only ! 465: 0.56 CPU seconds per sentence in a 23-sentence story. ! 466: .sp 3 ! 467: .PP ! 468: For measurements demonstrating the effectiveness of the hashing, ! 469: and comparisons between various implementations, see the section ! 470: below on performance. ! 471: .NH ! 472: Objects and Structures ! 473: .sp 3 ! 474: .PP ! 475: PEARL has four basic types: \fIinteger\fR, \fIsymbol\fR, \fIstructure\fR, ! 476: and \fIlisp\fR. ! 477: Objects of type \fBinteger\fR are the usual numeric type, and objects ! 478: of type \fBlisp\fR can be any non-atomic Lisp object. ! 479: \fBSymbols\fR (objects of type \fIsymbol\fR) correspond to atoms in Lisp, ! 480: and are simply primitive objects with predeclared unique labels. ! 481: There is a special built-in symbol \fBnilsym\fR ! 482: (corresponding to \fInil\fR when considered as an atom) ! 483: which denotes a value of type symbol carrying no special conceptual ! 484: information, that is, devoid of meaning. ! 485: \fBStructures\fR are collections of slots. ! 486: Each slot of a structure ! 487: may be filled with an object of one of the four types. ! 488: There is also a meta-type for slots, \fBsetof\fR, ! 489: which can be applied (recursively) to any basic type to generate a new type, ! 490: which will consist of a list of the specified type of objects. ! 491: There is a special built-in structure \fBnilstruct\fR respresenting ! 492: the standard empty structure (similar to \fInil\fR when considered ! 493: as the empty list). ! 494: .sp 3 ! 495: .PP ! 496: Types of structures must be predefined, with the number of slots, and ! 497: their names and types specified via a user declaration. ! 498: When an instance ! 499: of a structure is created and its slots filled, only objects with the ! 500: same type as the slot may fill it. ! 501: In addition, new structures may ! 502: build upon old ones in a hierarchical fashion by specifying new slots ! 503: to add to the old ones. ! 504: This hierarchy may be used in operations upon the data base. ! 505: .sp 3 ! 506: .PP ! 507: Since the data bases are hash tables (to be described in ! 508: more detail later), each symbol and type of structure is assigned ! 509: a unique integer at definition time to be used by the hash function ! 510: to compute a location in the hash table. ! 511: This contributes significantly to the speed of data base operations ! 512: in PEARL since it allows the hash function ! 513: to be a simple computation based on these numbers rather than ! 514: depending on the spelling of the names. ! 515: It also helps to prevent ! 516: structures with similar names from being hashed in similar ways. ! 517: In particular, the unique numbers 0 and 1 are automatically ! 518: assigned to \fInilsym\fR and \fInilstruct\fR. ! 519: .sp 3 ! 520: .PP ! 521: For example, symbols are declared as follows: ! 522: .DS ! 523: \fIpearl>\fB(symbol John Home Here) ! 524: \fI(John Home Here)\fR ! 525: .DE ! 526: .LP ! 527: This call to \fIsymbol\fR sets up three unique objects whose print ! 528: names are "John", "Home", and "Here" and associates with ! 529: them the next three unique integers (2, 3, and 4). ! 530: Note that the value returned is a \fIlist of the symbols created\fR, ! 531: not a list of Lisp atoms and PEARL's print function prints this ! 532: value out as \fI(John Home Here)\fR. ! 533: .sp 3 ! 534: .PP ! 535: The internal structure built by \fIsymbol\fR is a hunk of memory ! 536: big enough for two pointers pointing to the name and unique number. ! 537: .DS ! 538: Internal representat\kaion of the symbol John: ! 539: ! 540: s:John ---> \h'|\nau'Unique Number \kb---|---> 2 ! 541: \h'|\nau'Print Name \h'|\nbu'---|---> John ! 542: ! 543: .DE ! 544: .LP ! 545: Although we generally chose to use hunks of memory where possible ! 546: to save space (as demonstrated below), this representation ! 547: saves no space since it is equivalent to a cons-cell. ! 548: However, we chose to build it as a hunk and not a cons-cell since ! 549: in this way, PEARL can more easily distinguish it as a symbol ! 550: rather than a list cell. ! 551: The atom \fIs:John\fR is created with its value ! 552: set to the symbol John so that this unique symbol can be ! 553: generated at a later time, leaving the atom \fIJohn\fR available for ! 554: use by the user. ! 555: .sp 3 ! 556: .PP ! 557: New types of structures and instances of previously defined ! 558: types of structures are all created with the function \fBcreate\fR. ! 559: The statement ! 560: .DS ! 561: \fIpearl>\fB(create base Act ! 562: (Actor symbol) ) ! 563: \fI(Act (Actor nilsym))\fR ! 564: .DE ! 565: .LP ! 566: will define the primitive type \fIAct\fR with one slot named ! 567: \fIActor\fR and containing any single object of type symbol. ! 568: At the same time, \fIcreate\fR produces and returns an individual ! 569: instance known as the \fBdefault-instance\fR which contains the ! 570: standard default values for each slot. ! 571: PEARL also provides a ! 572: mechanism for changing these default values at definition time. ! 573: In this case, the slot Actor contains the default symbol \fInilsym\fR. ! 574: The other defaults are \fInilstruct\fR for structures, zero for integers ! 575: and \fInil\fR for slots of type \fIlisp\fR or \fIsetof\fR. ! 576: Again, the object returned by \fIcreate\fR is an internally represented ! 577: structure, not a list. ! 578: The representation of the definition and default-instance structures ! 579: internally as hunks of memory is as follows: ! 580: .DS ! 581: \klStructure definition for\km Act Default-instance for Act ! 582: ! 583: \h'|\nmu' <--------\kn| ! 584: \h'|\nlu'Unique Number \h'|\nmu'---|---> 5 \h'|\nnu'|----|---\koDefinition ! 585: \h'|\nlu'Length \h'|\nmu'---|---> 1 \h'|\nou'Var-List \kp---|---> nil ! 586: \h'|\nlu'Default Instance\h'|\nmu'---|---------->\h'|\nou'Var-List Copy \h'|\npu'---|---> nil ! 587: \h'|\nlu'Isa \h'|\nmu'---|---> nil ! 588: \h'|\nlu'Print Name \h'|\nmu'---|---> Act \h'|\nou'Value or Var Name \h'|\npu'---|---> nilsym ! 589: \h'|\nlu'Hash Alias \h'|\nmu'---|---> 0 \h'|\nou'Var-Value Pair \h'|\npu'---|---> nil ! 590: \h'|\nlu'Expansion List \h'|\nmu'---|---> nil \h'|\nou'Predicate List \h'|\npu'---|---> nil ! 591: \h'|\nlu'Base Ifs \h'|\nmu'---|---> nil \h'|\nou'Slot If List \h'|\npu'---|---> nil ! 592: ! 593: \h'|\nlu'Hash Information\h'|\nmu'---|---> 0 \h'|\nou' ^ ! 594: \h'|\nlu'Type Number \h'|\nmu'---|---> 0 \h'|\nou' | ! 595: \h'|\nlu'Slot Print Name\h'|\nmu'---|---> Actor \h'|\nou'i:Act ! 596: \h'|\nlu'PP Set Info \h'|\nmu'---|---> nil ! 597: \h'|\nmu' ^ ! 598: \h'|\nmu' | ! 599: \h'|\nmu'd:Act ! 600: .DE ! 601: .LP ! 602: There are many values in the above structure which are not yet ! 603: important to our discussion and which will be explained later. ! 604: The key values so far in the definition information are the unique ! 605: number, length of the structure (number of slots), the default ! 606: instance, and the print names of the structure itself and of its slot(s). ! 607: In the default instance note that a pointer to the definition is ! 608: kept in each instance to allow quick access to the unique number, ! 609: and other information during hashing and matching. ! 610: This means that the only time that a definition must be ! 611: accessed through its special atom (\fId:Act\fR in this case) ! 612: is when a new instance is created. ! 613: .sp 3 ! 614: .PP ! 615: The most important feature of this representation however, is the ! 616: speed gained by the use of hunks. ! 617: In order to represent this ! 618: information as an S-expression, we would need one cons-cell (space ! 619: for two pointers) per piece of information with half of this space ! 620: wasted on the pointer to the next cons-cell. ! 621: Accessing a particular piece of information would require ! 622: \fIcdr\fRing down the list an appropriate number of times ! 623: which is potentially quite slow with a larger number of slots. ! 624: Also, since this definition information is pointed to by all ! 625: instances, the uniqueness of at least its header ! 626: cell must be maintained requiring some extra effort on the ! 627: part of the programmer in Lisp. ! 628: However, given the cost of a cons-cell in terms of garbage ! 629: collection time, it would be best to maintain the uniqueness ! 630: of all of its parts. ! 631: .sp 3 ! 632: .PP ! 633: By using a hunk, we can ! 634: .IP 1) ! 635: easily guarantee the uniqueness of a definition or instance, ! 636: .IP 2) ! 637: save the space used by list pointers, thus using half the space, ! 638: .IP 3) ! 639: use no new cons-cells after a structure is created, ! 640: .IP 4) ! 641: access any piece of a structure in constant time ! 642: (essentially two adds and a multiply at the worst), and ! 643: .IP 5) ! 644: compile all access operations relatively efficiently. ! 645: .LP ! 646: Thus, the use of hunks rather than lists contributes significantly ! 647: to the speed of PEARL. ! 648: .sp 3 ! 649: .PP ! 650: Once we have defined the \fIbase\fR structure Act, ! 651: we can define more specific forms of Acts in terms of ! 652: it, using the \fBexpanded\fR argument to \fIcreate\fR in ! 653: place of \fIbase\fR: ! 654: .DS ! 655: \fIpearl>\fB(create expanded Act Trans ! 656: (From symbol) ! 657: (To symbol)) ! 658: \fI(Trans (Actor nilsym) ! 659: (From nilsym) ! 660: (To nilsym))\fR ! 661: .DE ! 662: .LP ! 663: Here, we are declaring that Transes (transfers) are Acts with ! 664: two additional slots for the initial location From and the final ! 665: location To which are both symbols. ! 666: In addition to the information ! 667: diagrammed above, the structure definitions for Act and Trans are now ! 668: connected via their Isa and Expansion List fields (that is, the Isa ! 669: field of Trans points to Act and Trans is an element of the ! 670: Expansion List field of Act. ! 671: In this way, a complete tree of the ! 672: concept hierarchy rooted at a base structure is accessible from any ! 673: element in that hierarchy. ! 674: .sp 3 ! 675: .PP ! 676: This hierarchy can be expanded to any depth. ! 677: Thus, we can now further ! 678: differentiate between various kinds of transfers, defining mental ! 679: transfers (MTrans) and physical transfers (PTrans). ! 680: In MTrans, the ! 681: mental object MObject slot will contain another concept and is thus ! 682: of type structure: ! 683: .DS ! 684: \fIpearl>\fB(create expanded Trans MTrans ! 685: (MObject struct)) ! 686: \fI(MTrans (Actor nilsym) ! 687: (From nilsym) ! 688: (To nilsym) ! 689: (MObject (nilstruct)))\fR ! 690: .DE ! 691: .DS ! 692: \fIpearl>\fB(create expanded Trans PTrans ! 693: (From Here) ! 694: (Object symbol)) ! 695: \fI(PTrans (Actor nilsym) ! 696: (From Here) ! 697: (To nilsym) ! 698: (Object nilsym))\fR ! 699: .DE ! 700: .LP ! 701: Slots which are not filled by the user when creating ! 702: an individual are filled in automatically with the default value ! 703: from the default instance. ! 704: Note in the definition of PTrans that we give the ! 705: default value of \fIHere\fR for the previously defined slot ! 706: \fIFrom\fR by simply including the slot and its new value. ! 707: This means that whenever we create an \fIindividual\fR instance ! 708: of PTrans but do not specify a value for the From slot, it will ! 709: be filled in with the value Here: ! 710: .DS ! 711: \fIpearl>\fB(create individual PTrans ! 712: (Actor John) ! 713: (Object John) ! 714: (To Home)) ! 715: \fI(PTrans (Actor John) ! 716: (From Here) ! 717: (To Home) ! 718: (Object John))\fR ! 719: .DE ! 720: .LP ! 721: This last structure denotes "John went home (from here)" in Schank's ! 722: Conceptual Dependency [11] theory of representation. ! 723: These representations are used in the rest of the paper simply ! 724: as an example of PEARL's use. ! 725: However, PEARL makes no commitment to any ! 726: particular set of predicates or primitives and can be used equally ! 727: well with any type of slot-filler structure. ! 728: .sp 3 ! 729: .PP ! 730: Slots within a structure may also be filled with a ! 731: pattern-matching variable, in which case the structure may ! 732: be viewed as a pattern. ! 733: The simplest form of pattern is one in which any unspecified ! 734: slots are filled with the \fImatch-anything\fR variable \fI?*any*\fR. ! 735: For example, a pattern matching any PTranses performed by John ! 736: could be defined as follows: ! 737: .DS ! 738: \fIpearl>\fB(create pattern PTrans ! 739: (Actor John)) ! 740: \fI(PTrans (Actor John) ! 741: (From ?*any*) ! 742: (To ?*any*) ! 743: (Object ?*any*))\fR ! 744: .DE ! 745: .LP ! 746: However, \fBany\fR individual PEARL structure, including one with ! 747: all of its slots filled with actual values, can be used as a ! 748: pattern. ! 749: Thus, the first individual PTrans created above is ! 750: a pattern which matches only instances of John Ptransing home ! 751: from Here. ! 752: The sole purpose of using the \fIpattern\fR option to ! 753: \fIcreate\fR rather than \fIindividual\fR is ! 754: to change the default value for all types of slots to \fI?*any*\fR. ! 755: Variables are indicated by preceding them with a question mark ! 756: as in ?X for the variable X and, other than \fI?*any*\fR, they are ! 757: bound as part of the matching process (usually during a ! 758: fetch from the data base) which is discussed further below. ! 759: PEARL also provides functions for accessing and changing the ! 760: values of slots within individual structures ! 761: and for automatically naming the structure created. ! 762: .sp 3 ! 763: .PP ! 764: Variables come in two other flavors in PEARL and are discussed in more ! 765: detail in the sections on matching and variables. ! 766: .NH ! 767: Data Base Facilities ! 768: .sp 3 ! 769: .PP ! 770: PEARL allows for a forest of associative data bases ! 771: into which structures may be placed, and later fetched ! 772: via structure patterns. ! 773: Since many AI programs spend a significant part of their time ! 774: searching for knowledge in growing data bases, this needs to ! 775: be as efficient as possible. ! 776: .sp 3 ! 777: .PP ! 778: Hashing is the usual programming solution to accessing a particular ! 779: element from within a large set. ! 780: However, traditionally, hashing has two prerequisites that are seldom ! 781: easy for an AI programmer to meet: ! 782: .IP 1) ! 783: The hash function must be carefully chosen in ! 784: advance to do a good job of spreading out the items to be inserted ! 785: with a minimum of computation. ! 786: In traditional applications of hash tables, this meant finding ! 787: a function which converts a (set of) string(s) into an index. ! 788: .IP 2) ! 789: Only completely specified items can be searched for. ! 790: That is, one may ! 791: not ask of a hash table "Find the closest one to X". ! 792: .LP ! 793: Unfortunately, since the knowledge structures used in AI are ! 794: much more complex than simple strings, finding a good hash ! 795: function is very difficult. ! 796: Also, in AI programming, normal hashing would only handle fetching ! 797: a particular fact from the data base, which would make the fetching ! 798: mean "Is this (completely specified) fact true?" ! 799: But it is much more likely that what is wanted is the (set of) thing(s) ! 800: which match a much more general pattern. ! 801: .sp 3 ! 802: .PP ! 803: For these reasons, hashing in the normal sense is ! 804: inappropriate for AI data bases. ! 805: As a result, the traditional solution to the need for efficient ! 806: indexing into an AI data base is the discrimination net. ! 807: Or, in some cases, the data base is reduced to a linear list with ! 808: its inefficiency ignored (or tolerated). ! 809: With a discrimination net, the user often must carefully determine ! 810: the structure of the net and the nature of the tests to be made at ! 811: each level. ! 812: This is necessary to reduce the breadth of the net at each level, ! 813: since a discrimination net usually implies a linear search through ! 814: the possible values at each branch point. ! 815: As the knowledge changes, the representation hierarchy must change ! 816: to avoid this breadth problem, drawing the programmer away from the ! 817: problem at hand into worrying about indexing every step of the way ! 818: and forcing the representation into unnatural distinctions. ! 819: Generalized pattern matching is also difficult, making questions ! 820: like "What in the data base is close to X?" hard to ask. ! 821: .sp 3 ! 822: .PP ! 823: Thus, a common problem with most AI data base implementations ! 824: is the system's lack of knowledge about how best to automatically ! 825: organize information for efficient and flexible retrieval. ! 826: The user usually has such knowledge, but needs to be able to provide ! 827: it in an easy way. ! 828: Moreover, if possible, this knowledge should be used to build a ! 829: hash table with its attendant speed, rather than a discrimination net. ! 830: The system must then provide a hash function which is ! 831: flexible enough to handle a large range of objects. ! 832: Such a hash table must also be organized in such a way that items may ! 833: be found which match a general pattern. ! 834: .sp 3 ! 835: .PP ! 836: PEARL provides such a hash table and hash function, designed in such a ! 837: way that the user gets a significant speed up with only the effort ! 838: required to define objects as already been described above. ! 839: In addition, PEARL encourages the user to provide as much extra ! 840: knowledge as possible when a structure type is defined. ! 841: The choice of a particular structure hierarchy does not affect the ! 842: efficiency of the hashing so the representations are not twisted ! 843: to achieve efficiency. ! 844: Since the purpose of a hash function is to scatter ! 845: similar items, the required information consists of ! 846: indicating those slots whose values are most likely ! 847: to distinguish two similar structures. ! 848: .sp 3 ! 849: .PP ! 850: This information is provided in the form of labels on ! 851: these slots in the definition of the structure. ! 852: Since only symbols and structures are assigned a unique integer at ! 853: definition time, slots of type \fIsymbol\fR, \fIstructure\fR ! 854: and \fIinteger\fR may contain such hashing information but slots ! 855: of type \fIlisp\fR may not. ! 856: These labels specify ways in which the unique number of the item being ! 857: hashed may be combined with the unique numbers associated with the ! 858: values of the labelled slots to provide a set of one, two, or three ! 859: numbers to be combined into an index into the hash table. ! 860: The particular ways of specifying these slots and the ! 861: ways of grouping them is described below, ! 862: but first we describe the form of a single data base and ! 863: the organization of a forest of data bases. ! 864: .sp 3 ! 865: .PP ! 866: Each data base is implemented as a pair of hash tables in which ! 867: each bucket is a list of the objects hashing to that spot. ! 868: The possible sizes of the data bases are chosen from the set of primes ! 869: which are just barely smaller than the powers of two, ! 870: (that is, 1, 3, 7, 13, 29, 61, 127, ...). ! 871: The two hash tables are chosen to be off by a factor of four, ! 872: (that is, 1+7, 3+13, ... 29+127, ...). ! 873: The two data bases are chosen to be of different sizes because ! 874: it was hard to find a hash function to provide a good spread ! 875: in a large table for single small integers like the unique numbers ! 876: associated with structures. ! 877: The currently-used hash functions can be described as follows: ! 878: .DS ! 879: Let Size1 and Size2 be the sizes of the two hash tables. ! 880: Then the hash functions are: ! 881: ! 882: For indexes based on one number X: ! 883: X mod Size1 ! 884: For indexes based on two numbers X and Y: ! 885: (4096 * Y + X ) mod Size2 ! 886: For indexes based on three numbers X, Y and Z: ! 887: ( (4096 * 4096 * Z) + (4096 * Y) + X ) mod Size2 ! 888: .DE ! 889: .LP ! 890: Thus the smaller of the two hash tables is used to enter ! 891: items indexed under only one unique number. ! 892: The larger is used for items indexed under combinations of ! 893: two or three numbers. ! 894: The sizes for hash tables can be chosen by the user to match the ! 895: number and variety of objects, the number of data bases being used ! 896: and the size of their machine's memory. ! 897: .sp 3 ! 898: .PP ! 899: In order to allow flexible fetching using a pattern which is only ! 900: partly specified, and since the place we look must be determined based ! 901: upon the information that \fIis\fR provided in the pattern, ! 902: an item must be placed everywhere we are likely to be able to ! 903: look for it. ! 904: Thus, PEARL will index all individual instances of a structure type ! 905: which are inserted into the data base ! 906: under as many different hashing strategies as it can, ! 907: using the information provided by the user in the ! 908: definition of that type of structure. ! 909: Then to fetch with a particular pattern, PEARL need only use one of ! 910: the hashing strategies which uses slots from the pattern whose ! 911: values are considered hashable. ! 912: .sp 3 ! 913: .PP ! 914: Whether there is hashing information or not, all individuals are ! 915: indexed in the smaller data base under (the unique integer ! 916: assigned to) their structure type. ! 917: Thus, with no effort, the user automatically gets one level ! 918: of distinction which provides a significant improvement ! 919: in efficiency over the often-used linked list. ! 920: This minimal use of hashing in PEARL is also an ! 921: improvement over discrimination nets since nets usually ! 922: imply a linear search through the possible values at each ! 923: branch point of the net instead of random access. ! 924: Of course, if the number of types of structures is ! 925: larger than the size of the data base, then after this random access, ! 926: there is still potentially a list of items to be searched linearly. ! 927: .sp 3 ! 928: .PP ! 929: At this point, the speed with which the matching process ! 930: eliminates structures of the wrong type becomes important. ! 931: But the easily available unique number in each item provides a quick ! 932: test to eliminate items of the wrong type. ! 933: (For a complete description of the matching process, see the section on ! 934: predicates and matching.) ! 935: .sp 3 ! 936: .PP ! 937: However, no amount of speed-up of the matching process can help as ! 938: much as a greater degree of discrimination by the hash function. ! 939: So to improve upon this automatic type of hashing, PEARL ! 940: needs to know which slots or collections of slots of a structure ! 941: are likely to help split up objects of the same type. ! 942: We will now describe each of the available hashing methods and the ! 943: circumstances in which you would want to use them. ! 944: .sp 3 ! 945: .PP ! 946: The simplest case of adding hashing information is to label slots ! 947: whose values, in combination with the type of structure, would provide ! 948: a good distinction. ! 949: To indicate that a particular slot is useful in this way, ! 950: the user puts an asterisk (*) in that slot in the declaration. ! 951: Thus ! 952: .DS ! 953: \fIpearl>\fB(create base PlanFor ! 954: (* Goal struct) ! 955: ( Plan struct)) ! 956: \fI(PlanFor (Goal (nilstruct)) ! 957: (Plan (nilstruct)))\fR ! 958: .DE ! 959: .LP ! 960: defines a type PlanFor with slots for a goal and a plan, and indicates that ! 961: PlanFors should be indexed to be retrieved by the content of ! 962: their Goal slot plus the fact that they are PlanFors. ! 963: PEARL then uses the unique integers associated with the PlanFor ! 964: type and with whatever type of value is in the Goal slot. ! 965: .sp 3 ! 966: .PP ! 967: Since the object filling the Goal slot of a PlanFor will always be ! 968: a structure of type Goal, using an asterisk in the Goal slot will not ! 969: actually distinguish PlanFors from one another. ! 970: In this case, we may ! 971: also wish to specify that the value that fills the Goal slot is to be ! 972: used to in a slightly different way to create the index. ! 973: For example, if the Objective of the Goal ! 974: is deemed more significant for such purposes than the fact that it ! 975: is a Goal, we can indicate this as follows: ! 976: .DS ! 977: \fIpearl>\fB(create base Goal ! 978: ( Planner symbol) ! 979: (& Objective struct)) ! 980: \fI(Goal (Planner nilsym) ! 981: (Objective (nilstruct)))\fR ! 982: .DE ! 983: .LP ! 984: This will inform PEARL that structures that indexing on slots ! 985: in other structures which are filled with Goal-type structures ! 986: should instead use the Objective slot for further discriminations. ! 987: Thus, Goals change the way in which other structures use them to ! 988: index but the way in which Goals themselves are indexed ! 989: will not be affected. ! 990: This hash labelling of Goal is called \fBhash aliasing\fR and ! 991: will cause all PlanFors to be indexed ! 992: under the number for the PlanFor type plus the number for the type of value in ! 993: the Objective slot of the Goal, and thus all PlanFor's for Goals for a ! 994: particular type of Objective will be indexed in the same bucket. ! 995: As a short hand, the phrase "indexed under the number for the PlanFor ! 996: type plus the number for the type of value in the Objective slot of ! 997: Goal" is abbreviated as "PlanFor + Objective(Goal)" ! 998: .sp 3 ! 999: .PP ! 1000: It might be the case that PlanFor was the only structure ! 1001: indexed based on Goals which would benefit from this and that ! 1002: some structures would actually be hurt by this because they ! 1003: expected Goals to be only one of many types of values. ! 1004: In this case, putting the control of how Goals get used by ! 1005: other structures into the definition of Goal is a bad idea. ! 1006: Instead, the control can be moved up into only the ! 1007: problematic structures. ! 1008: These structures can simply add the ">" hash label to ! 1009: a starred slot, causing PEARL to use the first starred slot of ! 1010: the slot-filling structure instead of its type. ! 1011: .DS ! 1012: \fIpearl>\fB(create base Goal ! 1013: (Planner symbol) ! 1014: (* Objective struct)) ! 1015: \fI(Goal (Planner nilsym) ! 1016: (Objective (nilstruct)))\fR ! 1017: .DE ! 1018: .DS ! 1019: \fIpearl>\fB(create base PlanFor ! 1020: (* > Goal struct) ! 1021: (Plan struct)) ! 1022: \fI(PlanFor (Goal (nilstruct)) ! 1023: (Plan (nilstruct)))\fR ! 1024: .DE ! 1025: .LP ! 1026: If the user wanted to also star the Planner slot of Goal, ! 1027: but wanted the Objective slot to be used in cases where the ! 1028: containing structure had a ">", ! 1029: then the use of an "^" on the Objective slot will allow that: ! 1030: .DS ! 1031: \fIpearl>\fB(create base Goal ! 1032: (* Planner symbol) ! 1033: (* ^ Objective struct)) ! 1034: \fI(Goal (Planner nilsym) ! 1035: (Objective (nilstruct)))\fR ! 1036: .DE ! 1037: .LP ! 1038: thus allowing Goals inserted directly into the data base to be ! 1039: indexed by the combinations (Goal + Planner(Goal)) and ! 1040: (Goal + Objective(Goal)) while objects containing Goals would ! 1041: use the Objective slot rather than Goal (Object + Objective(Goal)). ! 1042: If most structures containing Goals would benefit from the use of ! 1043: the hash aliasing label & in Goal, but only one or two are hurt by it, ! 1044: the use of "&" in Goal can be overridden by the structures ! 1045: which will contain Goals by adding the "<" hash label to the starred ! 1046: slot, thus giving the controlling structure the last word over how ! 1047: it is hashed. ! 1048: .DS ! 1049: \fIpearl>\fB(create base Goal ! 1050: ( Planner symbol) ! 1051: (& Objective struct)) ! 1052: \fI(Goal (Planner nilsym) ! 1053: (Objective (nilstruct)))\fR ! 1054: .DE ! 1055: .DS ! 1056: \fIpearl>\fB(create base OffendedStructure ! 1057: (* < Slot struct)) ! 1058: \fI(OffendedStructure (Slot nilstruct)))\fR ! 1059: .DE ! 1060: .sp 3 ! 1061: .PP ! 1062: The above methods are all designed to allow the indexing of a ! 1063: structure to be based upon the type of structure and the type of the ! 1064: value of one slot. ! 1065: There are sometimes cases where one slot is not ! 1066: enough to distinguish items sufficiently but two slots would do a much ! 1067: better job. ! 1068: For example, a program which dealt with a large number of ! 1069: Goals of several planners might want to be able to ask whether a ! 1070: particular planner had a particular objective. ! 1071: Putting an asterisk in each of the slots of Goal would allow ! 1072: hashing by one or the other, but it would be even faster to use the ! 1073: fact it was a Goal, plus the values of both the Planner and Objective ! 1074: slots. ! 1075: Labelling this pair of slots with "**" causes their values ! 1076: plus the structure type to be combined into an index. ! 1077: .DS ! 1078: \fIpearl>\fB(create base Goal ! 1079: (* ** Planner symbol) ! 1080: (* ** Objective struct) ) ! 1081: \fI(Goal (Planner nilsym) ! 1082: (Objective (nilstruct) ) )\fR ! 1083: .DE ! 1084: .LP ! 1085: This is also useful whenever the range of types of values in ! 1086: each slot is limited but the combinations of the two ! 1087: have a wider range. ! 1088: .sp 3 ! 1089: .PP ! 1090: On the other hand, it may sometimes be useful to know all ! 1091: structures containing a particular type of value in any prominent ! 1092: slots. ! 1093: Thus for example, if a program has many kinds of structures all ! 1094: containing references to individual planners, it might be useful ! 1095: to be able to efficiently ask the question "What do I know about ! 1096: John?". ! 1097: In this case, the use of a ":" hash label on those slots of relevant ! 1098: structures which contain Planners causes all those ! 1099: structure to be indexed by that slot's value only, without ! 1100: regard to the structure type. ! 1101: This would result in some bucket in the smaller data base to contain ! 1102: all structures which refer to John in such a labelled slot, ! 1103: because they would all be indexed under that single value. ! 1104: Note that this is similar to the "&" type of hashing, ! 1105: but affects the structure itself instead of containing structures. ! 1106: .sp 3 ! 1107: .PP ! 1108: Finally, there is a hash labelling which is the combination ! 1109: of these last two ideas. ! 1110: It may sometimes be useful to know all structures containing a two ! 1111: particular types of values in prominent slots. ! 1112: Thus for example, if a program has many kinds of acts and states ! 1113: all containing references to individual person/object and the time ! 1114: of occurrence, it might be useful to be able to efficiently ask ! 1115: the question "What did John do at 8 o'clock?". ! 1116: Thus, the use of a single pair of slots (in each structure) labelled ! 1117: with "::" causes the value of those two slots to be combined ! 1118: into an index. ! 1119: .DS ! 1120: \fIpearl>\fB(create base Act ! 1121: (:: Actor struct) ! 1122: (:: Time int) ) ! 1123: \fI(Act (Actor (nilstruct)) ! 1124: (Time 0) )\fR ! 1125: \fIpearl>\fB(create base State ! 1126: (:: Object struct) ! 1127: (:: Time int) ) ! 1128: \fI(State (Object (nilstruct)) ! 1129: (Time 0) )\fR ! 1130: .DE ! 1131: In this case, all states of John or acts by John would be indexed ! 1132: under John plus the time, thus ending up in the same hash bucket. ! 1133: .sp 3 ! 1134: .PP ! 1135: The hashing mechanism was designed to give the user benefit in ! 1136: proportion to the effort expended in determining hash labels. ! 1137: With no effort, the structure type provides some help. ! 1138: With the addition of each label or pair of labels, ! 1139: an item to be inserted into the data base is indexed into ! 1140: another location in the hash table. ! 1141: Thus the cost of extra labels is simply the time to find ! 1142: another hash bucket (a few adds and multiplies), and add ! 1143: the item to the front of the list implying the time and ! 1144: space incurred by one cons-cell. ! 1145: The benefit at fetching time is the ability to use this ! 1146: extra information to narrow in on a small subset of ! 1147: the items in the data base which are most likely to ! 1148: be what is desired. ! 1149: .sp 3 ! 1150: .PP ! 1151: It is often the case that a program needs to build several ! 1152: data bases where one or more are extensions of another. ! 1153: For example, consider a planner which is trying to choose ! 1154: between two alternative plans. ! 1155: One way to do this is to simulate carrying each one out to ! 1156: determine its likely effects (good or bad) to help in the ! 1157: decision. ! 1158: Thus the program might want to build a data base for each ! 1159: into which it could assert the various facts determined by ! 1160: the simulation. ! 1161: Both of these new data bases would be considered extensions of the ! 1162: usual data base with the added feature that anything stored in ! 1163: them was simply expected to be true in the future. ! 1164: Thus, after the simulation, it might be desireable to delete the ! 1165: data base of the plan not chosen and the program would certainly ! 1166: not want to assert the effects of the simulation into its regular ! 1167: data base since they are not in fact true. ! 1168: .PP ! 1169: PEARL provides both these abilities by providing facilities for ! 1170: building a forest of data bases. ! 1171: The regular data base which is built automatically is called ! 1172: \fI*maindb*\fR. ! 1173: To build two extensions from this, one uses the function ! 1174: \fIbuilddb\fR: to build a tree of data bases: ! 1175: .DS ! 1176: \fIpearl>\fB(builddb Test1 *maindb*) ! 1177: \fI(database: Test1)\fR ! 1178: \fIpearl>\fB(builddb Test2 *maindb*) ! 1179: \fI(database: Test2)\fR ! 1180: .DE ! 1181: .LP ! 1182: We can then assert various facts from the simulation into each of ! 1183: these new data bases. ! 1184: If we subsequently fetch from Test1, we will get back all facts ! 1185: which were asserted into either \fITest1 \fBor \fI*maindb*\fR. ! 1186: When we have decided which to use, we can then free up the one ! 1187: that is no longer needed. ! 1188: .NH ! 1189: Fetching ! 1190: .sp 3 ! 1191: .PP ! 1192: To fetch an object from a data base, the user invokes the ! 1193: fetcher with a structure to be used as a pattern. ! 1194: For efficiency, ! 1195: PEARL tries to narrow down the possible choices without ! 1196: actually matching this pattern against any knowledge in the ! 1197: data base. ! 1198: Thus, narrowing down the possibilities and avoiding ! 1199: matching as long has possible are the two driving goals of the ! 1200: fetching algorithm. ! 1201: In order to narrow down the choices, ! 1202: information in the pattern is examined to determine ! 1203: which of the hashing indices is most likely to narrow ! 1204: down the choices. ! 1205: This determination is made based on the ways in which PEARL has been ! 1206: instructed to hash structures of the same type as the pattern and also ! 1207: based on which slots of the pattern actually have a useful value for ! 1208: hashing. ! 1209: \fINilsym\fR, \fInilstruct\fR, \fInil\fR and \fIunbound\fR values ! 1210: are not considered useful. ! 1211: Given the values which are considered useful and the hashing ! 1212: information for the type of structure, the hierarchy of buckets to be ! 1213: chosen is as follows: ! 1214: .DS ! 1215: ** hashing ! 1216: :: hashing ! 1217: * hashing ! 1218: : hashing ! 1219: .DE ! 1220: .LP ! 1221: All the other hashing labels are modifiers on these four ! 1222: methods and affect what values are used to compute the index. ! 1223: .sp 3 ! 1224: .PP ! 1225: The resulting hash index is used to choose a bucket from the hash ! 1226: table which is returned to the user as a result stream. ! 1227: No matching between the pattern and objects ! 1228: in the data base occurs at this point and the ! 1229: stream simply contains pointers to all data base items ! 1230: in the same hash bucket, regardless of whether they actually ! 1231: match the pattern. ! 1232: PEARL appends the pattern to the front of this ! 1233: stream for subsequent use. ! 1234: For example, to fetch all PlanFors involving Goals whose Objective ! 1235: is a PTrans, we create a pattern for this type of object: ! 1236: .DS ! 1237: \fIpearl>\fB(setq PTransGoals (create pattern PlanFor ! 1238: (Goal (Goal (Objective (PTrans)))) ! 1239: (Plan ?Plan))) ! 1240: \fI(PlanFor (Goal (Goal (Planner ?*any*) ! 1241: (Objective (PTrans (Actor ?*any*) ! 1242: (Object ?*any*) ! 1243: (From ?*any*) ! 1244: (To ?*any*))))) ! 1245: (Plan ?Plan))\fR ! 1246: .DE ! 1247: .LP ! 1248: and then call the function \fBfetch\fR with this pattern as an ! 1249: argument: ! 1250: .DS ! 1251: (setq PTransGoalStream (fetch PTransGoals)) ! 1252: .DE ! 1253: .sp 3 ! 1254: .PP ! 1255: The user may then extract items from ! 1256: the stream one at a time by successive requests to \fBnextitem\fR: ! 1257: .DS ! 1258: (setq Result (nextitem PTransGoalStream)) ! 1259: .DE ! 1260: .LP ! 1261: At each request, the pattern is matched against successive ! 1262: items from the hash bucket until one matches, ! 1263: in which case it is returned, ! 1264: or until the potential items run out, ! 1265: in which case \fInil\fR is returned. ! 1266: .NH ! 1267: Predicates and Matching ! 1268: .sp 3 ! 1269: .PP ! 1270: Predicates may also be attached to a slot specifying constraints on ! 1271: the values of pattern-matching variables. ! 1272: Each time a match is made between the slots of two structures ! 1273: (described in detail below), the predicates of each slot are run to ! 1274: determine whether the match should succeed or fail. ! 1275: Two types of predicates are provided by PEARL. ! 1276: The first type are Lisp functions or expressions to be evaluated. ! 1277: If a predicate is simply the name of a function, that function is ! 1278: applied to the slot value from the opposing structure. ! 1279: If it is an S-expression, it is processed for special forms ! 1280: which indicate where to get the arguments and then evaluated. ! 1281: For example, the following pattern will require that the variable in ! 1282: its first slot be bound to a positive integer value with the predicate ! 1283: \fIplusp\fR. ! 1284: It also requires that the variable in its third slot be bound ! 1285: to a value which is a member of its second slot (\fB"*"\fR refers ! 1286: to the value in the current slot of the opposing structure and ! 1287: \fI"=Two"\fR refers to the value in the slot named Two of the ! 1288: opposing structure): ! 1289: .DS ! 1290: \fIpearl>\fB(create individual Example ! 1291: (One ?One plusp) ! 1292: (Two ?*any*) ! 1293: (Three ?Three (member * =Two) ) ) ! 1294: \fI(Example (One ?One) ! 1295: (Two ?*any*) ! 1296: (Three ?Three) )\fR ! 1297: .DE ! 1298: .sp 3 ! 1299: .PP ! 1300: The second type of predicate is called a \fBstructure predicate\fR and ! 1301: consists of the name of a structure type. ! 1302: Its effect is to restrict the value in a structure slot to being a ! 1303: structure of the specified type. ! 1304: Thus another way to restrict the value of the Objective of the Goal in ! 1305: the Goal slot of the PlanFor which was fetched above, is to put a variable ! 1306: in the slot and add a PTrans predicate: ! 1307: .DS ! 1308: \fIpearl>\fB(setq PTransGoals (create pattern PlanFor ! 1309: (Goal (Goal (Objective ?O PTrans))) ! 1310: (Plan ?Plan))) ! 1311: \fI(PlanFor (Goal (Goal (Planner ?*any*) ! 1312: (Objective ?O))) ! 1313: (Plan ?Plan))\fR ! 1314: .DE ! 1315: .LP ! 1316: The effect is the same but testing the type of the value is much more ! 1317: efficient than doing the matching process on the two PTranses slot by ! 1318: slot. ! 1319: .sp 3 ! 1320: .PP ! 1321: For efficiency, the semantics of the matching have been ! 1322: constrained to avoid the usual variable naming problems. ! 1323: Two structures match if they can be unified. ! 1324: However, no attempt is made to detect circularities, ! 1325: nor are variables ever bound to other variables. ! 1326: Circularities have never actually occurred in our experience and ! 1327: most variables are local to the pattern they appear in, ! 1328: so naming conflicts do not arise. ! 1329: Of course it would be straightforward to add checks for ! 1330: these problems if one was willing to incur the expense. ! 1331: .sp 3 ! 1332: .PP ! 1333: The variables in a structure are implemented as an assoc-list attached ! 1334: to the structure so that a list of the variables of a structure can be ! 1335: located quickly. ! 1336: However, \fIassoc\fR is only used for external lookup of a variable. ! 1337: Once the structure has been created, each slot containing a variable ! 1338: has a pointer to the special cons-cell associated with it in the ! 1339: assoc-list so that it has immediate access to its value. ! 1340: In particular, the name of the variable is not even accessed during ! 1341: the matching process, since its value is all that is needed. ! 1342: .sp 3 ! 1343: .PP ! 1344: In general, the matching procedure takes two structures ! 1345: which each may contain variables. ! 1346: If the structures are not definitionally the same type ! 1347: then the match fails automatically. ! 1348: This quickly eliminates items which happen to hash to the same slot. ! 1349: Otherwise, each structure is viewed as a sequence of slots ! 1350: which are successively matched between the two structures. ! 1351: Two structures of the same type match if and only if each of their ! 1352: slots matches the corresponding slot of the other structure. ! 1353: Each slot is filled in one of three ways: ! 1354: .IP 1) ! 1355: The slot may contain an actual value of its type (for example, ! 1356: a slot of type \fIstructure\fR may contain a PTrans). ! 1357: .IP 2) ! 1358: The slot may contain a user-defined variable. ! 1359: .IP 3) ! 1360: The slot may contain the special match-anything variable \fI?*any*\fR. ! 1361: .LP ! 1362: If the slot contains a variable (other than \fI?*any*\fR) which has not ! 1363: been bound then it may become bound as a side effect of the ! 1364: matching process. ! 1365: Once a variable is bound to a real value during the ! 1366: matching process, for the purposes of matching, it will ! 1367: be treated as if the slot were filled with that value. ! 1368: .sp 3 ! 1369: .PP ! 1370: We now examine each of the pairings of slot values which may ! 1371: occur and how they are matched. ! 1372: If either of the two slots being matched contains the special ! 1373: variable \fI?*any*\fR, then the slots match by definition, ! 1374: regardless of the contents of the other slot. ! 1375: If both slots contain variables that are unbound, the slots do not ! 1376: match. ! 1377: (This is true even if the two variables are textually ! 1378: the same name, since they are each considered local to their ! 1379: particular structures.) ! 1380: If one slot contains an unbound variable (and the other ! 1381: a bound variable or a value), then any predicates on the ! 1382: slot with the unbound variable are tested to see if the ! 1383: unbound variable should be bound to the bound value. ! 1384: If so, then the unbound variable is bound to the value ! 1385: of the other slot, and the two slots match. ! 1386: If any of the predicates return \fInil\fR, the two slots do not ! 1387: match, the variable is not bound, and the entire match fails. ! 1388: .sp 3 ! 1389: .PP ! 1390: If both slots contain either bound variables or values, ! 1391: then the values of the two slots are compared. ! 1392: If the slot is of type \fIstructure\fR, then the entire matching ! 1393: algorithm is recursively applied. ! 1394: If the slot is of types \fIinteger\fR or \fIlisp\fR, then \fIequal\fR is used. ! 1395: If the type is \fIsymbol\fR, than the two values must be the same symbol. ! 1396: Regardless of the type, any predicates associated with the ! 1397: slot are run and all must succeed. ! 1398: .sp 3 ! 1399: .PP ! 1400: For example, if we create two structures, one representing Sam ! 1401: and one with a variable in the \fIName\fR slot: ! 1402: .DS ! 1403: \fIpearl>\fB(create individual Person Sam ! 1404: (Name Samuel)) ! 1405: \fI(Person (Name Samuel))\fR ! 1406: \fIpearl>\fB(create individual Person PersonPattern ! 1407: (Name ?FirstName)) ! 1408: \fI(Person (Name ?FirstName))\fR ! 1409: .DE ! 1410: .LP ! 1411: then match them and look at the result in \fIPersonPattern\fR: ! 1412: .DS ! 1413: \fIpearl>\fB(match Sam PersonPattern) ! 1414: \fIt\fR ! 1415: \fIpearl>\fBPersonPattern ! 1416: \fI(Person (Name ?FirstName = Samuel))\fR ! 1417: .DE ! 1418: .LP ! 1419: we find that they do match and the variable \fI?FirstName\fR in ! 1420: \fIPersonPattern\fR has been bound to the symbol \fISamuel\fR. ! 1421: .PP ! 1422: We now take a slightly more complicated example. ! 1423: In PEARL's matching algorithm there is no sense that one of its ! 1424: arguments is the pattern and one the thing to be matched to, so ! 1425: both may have variables. ! 1426: As long as the variables are in different slots so that \fImatch\fR ! 1427: will never try to match two unbound variables to each other, the ! 1428: matching will work fine. ! 1429: Thus, if we want our backward inference mechanism from the extended ! 1430: example in section 2 to not only tell us \fIthat\fR Sam has a low ! 1431: salary but in fact \fIwhat level\fR of salary he had, we could ! 1432: fetch the following structure: ! 1433: .DS ! 1434: .Ls ! 1435: (create \kBindividual Salary SamsSalary ! 1436: \h'|\nBu'\kA(Employee Sam) ! 1437: \h'|\nAu'(Level ?Level)) ! 1438: .Le ! 1439: .DE ! 1440: .LP ! 1441: This would result in the backward inference demon using the ! 1442: following pattern to fetch rules that might tell it about ! 1443: finding a person's salary: ! 1444: .DS ! 1445: \fIpearl> \fB(create pattern BackwardRule Wanted ! 1446: (Need (Salary (Employee Sam) ! 1447: (Level ?Level)))) ! 1448: \fI(BackwardRule (Need (Salary (Employee (Person (Name Sam))) ! 1449: (Level ?Level))) ! 1450: (LookFor ?*any*))\fR ! 1451: .DE ! 1452: .LP ! 1453: In processing the resulting stream, the matcher would be called ! 1454: upon to match the above pattern \fIWanted\fR to the following ! 1455: rule (which is in the data base but which we recreate for ! 1456: this example): ! 1457: .DS ! 1458: \fIpearl> \fB(create individual BackwardRule Known ! 1459: (Need (Salary (Employee ?Person) ! 1460: (Level Low))) ! 1461: (LookFor (Professor (Person ?Person)))) ! 1462: \fI(BackwardRule (Need (Salary (Employee ?Person) ! 1463: (Level Low))) ! 1464: (LookFor (Professor (Person ?Person))))\fR ! 1465: .DE ! 1466: Matching these will succeed and in the process the variables ! 1467: \fI?Level\fR in \fIWanted\fR and \fI?Person\fR in \fIKnown\fR ! 1468: will be bound: ! 1469: .DS ! 1470: \fIpearl> \fB(match Wanted Known) ! 1471: \fIt\fR ! 1472: \fIpearl> \fBWanted ! 1473: \fI(BackwardRule (Need (Salary (Employee (Person (Name Sam))) ! 1474: (Level ?Level = Low))) ! 1475: (LookFor ?*any*))\fR ! 1476: \fIpearl> \fBKnown ! 1477: \fI(BackwardRule (Need (Salary (Employee ?Person = (Person (Name Sam))) ! 1478: (Level Low))) ! 1479: (LookFor (Professor (Person ?Person ! 1480: = (Person (Name Sam))))))\fR ! 1481: .DE ! 1482: .NH ! 1483: Variables ! 1484: .sp 3 ! 1485: .PP ! 1486: There are three types of pattern matching variables in PEARL. ! 1487: Global variables (which are just Lisp variables) must be declared ! 1488: and are never unbound by PEARL. ! 1489: All undeclared variables are local to the individual structure in ! 1490: which they are mentioned. ! 1491: Local variables are dummy variables, local to a particular ! 1492: structure and any of its components which were created ! 1493: in the same instant. ! 1494: They are all unbound by PEARL before every match on that structure. ! 1495: The examples given of variables in the previous section were of local ! 1496: variables which require no declaration. ! 1497: The third, intermediate, type of variable provides lexical ! 1498: scoping within groups of structures. ! 1499: Lexically scoped variables are like local variables in that they ! 1500: are unbound by PEARL before a match is made, but have their ! 1501: scope extended across several structures as indicated by the user. ! 1502: .sp 3 ! 1503: .PP ! 1504: Consider the following examples of the three types of variables. ! 1505: For our first example, suppose that in a data base representing the ! 1506: planning knowledge of a particular person is an Ego structure which ! 1507: records the identity of that person. ! 1508: The program wishes to determine this and to remember it in a variable ! 1509: called Planner. ! 1510: Planner is declared to be global and then used to fetch the ! 1511: appropriate knowledge structure from the data base: ! 1512: .DS ! 1513: .Ls ! 1514: (global Planner) ! 1515: (nextitem (fetch (create \kAindividual Ego ! 1516: \h'|\nAu'(Identity ?Planner)))) ! 1517: .Le ! 1518: .DE ! 1519: .LP ! 1520: At this point, the Lisp atom Planner is bound to the ! 1521: identity of the planner. ! 1522: We can now ask for all PTranses in the data base involving the planner ! 1523: as the Actor and Object: ! 1524: .DS ! 1525: .Ls ! 1526: (setq Pat (create \kBindividual Ptrans ! 1527: \h'|\nBu'\kA(Actor ?Planner) ! 1528: \h'|\nAu'\kB(Object ?Planner) ! 1529: \h'|\nBu'\kA(From ?Start) ! 1530: \h'|\nAu'(To ?Dest))) ! 1531: (setq Stream (fetch Pat)) ! 1532: .Le ! 1533: .DE ! 1534: .LP ! 1535: At this point the pattern in Pat has two local variables, ! 1536: \fI?Start\fR and \fI?Dest\fR which will be unbound before each match and ! 1537: may be bound to a new value during each match. ! 1538: \fI?Planner\fR on the other hand is global and will continue to have the ! 1539: value it received during the original fetch it was used in. ! 1540: .sp 3 ! 1541: .PP ! 1542: With a global variable, a group of structures are allowed to share a ! 1543: variable whose value is constant once it is set the first time. ! 1544: Furthermore, all structures are thereafter required to share this same ! 1545: variable and are precluded from having their own variable with the ! 1546: same name. ! 1547: However, it is sometimes useful to group a set of structures together ! 1548: via a set of variables which we wish to behave like local variables in ! 1549: every other way. ! 1550: Furthermore we might wish to have several such groups which can each ! 1551: have a variable with this same name. ! 1552: For example, a body of PEARL structures conceptually composing a ! 1553: single frame should be made to share the same variables but it should ! 1554: be possible to have several instances of such a frame with the same ! 1555: variable names tying each group together without interfering with the ! 1556: others. ! 1557: Each instance of this group of variables is then local to that frame. ! 1558: However, the results of matching any particular component ! 1559: of the frame will be detectable in the variables associated ! 1560: with the other components. ! 1561: This is done in PEARL by dynamically declaring a scope with local ! 1562: variables which are imposed upon all structures created until that ! 1563: scope is closed. ! 1564: For example, consider the following sequence: ! 1565: .DS ! 1566: .Ls ! 1567: (block Plan1 (Planner Goal)) ! 1568: (create \kBindividual PlanFor ! 1569: \h'|\nBu'\kA(Goal ?Goal) ! 1570: \h'|\nAu'(Plan ?Plan)) ! 1571: (create \kBindividual Goal ! 1572: \h'|\nBu'\kA(Planner ?Planner) ! 1573: \h'|\nAu'(Objective ?Objective)) ! 1574: (create \kAindividual Plan ! 1575: \h'|\nAu'\kB(Planner ?Planner) ! 1576: \h'|\nBu'\kA(Goal ?Goal) ! 1577: \h'|\nAu'(Steps ?Steps)) ! 1578: (endblock Plan1) ! 1579: .Le ! 1580: .DE ! 1581: .LP ! 1582: This sequence creates three structures which are intimately tied ! 1583: together via the variables \fI?Planner\fR and \fI?Goal\fR which ! 1584: are declared in the enclosing block. ! 1585: After this code executes, if any of the structures is fetched from ! 1586: the data base, any binding of these two variables would have an ! 1587: immediate effect in all of them. ! 1588: In addition, the values of these variables are available simply by ! 1589: knowing the name of the block, so that one can ask for the value of ! 1590: the Planner variable in Plan1 directly. ! 1591: However, now that the block has been closed, other structures are ! 1592: free to have variables with the same names. ! 1593: .NH ! 1594: Demons ! 1595: .sp 3 ! 1596: .PP ! 1597: A common AI mechanism provided by AI languages is one of ! 1598: "if-added" functions or demons. ! 1599: PEARL has a general ability to attach functions called \fIhooks\fR ! 1600: to base structures (\fIbase hooks\fR) or to slots of individual ! 1601: structures (\fIslot hooks\fR). ! 1602: Base hooks are run whenever the particular PEARL function that the ! 1603: hook is labelled with accesses an individual of that type. ! 1604: Slot hooks are put into individual and are run whenever the particular ! 1605: PEARL function that the hook is labelled with accesses that slot ! 1606: of the individual. ! 1607: In order to allow these hooks to tailor the operation of the ! 1608: various PEARL functions on particular structures or types of ! 1609: structures, these demons may be invoked either before or after ! 1610: the PEARL function they are labelled with does its work. ! 1611: If they run before, they are allowed to short-circuit the function's ! 1612: action or perform it themselves and specify a value to return. ! 1613: If they run after, they may also modify the value to be returned. ! 1614: .sp 3 ! 1615: .PP ! 1616: For example, in the extended example at the beginning of this ! 1617: paper, we presented a simple inference package which would run ! 1618: automatically whenever an object was fetched or inserted. ! 1619: To implement this, we wrote two functions MakeForwardInference ! 1620: and MakeBackwardInference. ! 1621: MakeForwardInference was designed to use rules which said if ! 1622: you learn X then infer Y. ! 1623: MakeBackwardInference was designed to use rules which said if ! 1624: you want to know X then check to see if you know Y. ! 1625: Learning something while using PEARL usually means inserting ! 1626: something into the data base, so we wish to have ! 1627: MakeForwardInference run whenever we insert some concept ! 1628: into the data base, after the insertion. ! 1629: Wanting to know something while using PEARL means fetching ! 1630: it from the data base, so we wish to have MakeBackwardInference ! 1631: run whenever we fetch some concept from the data base, before the ! 1632: actual fetch takes place. ! 1633: This was accomplished by attaching these two functions as demons ! 1634: to the base structure Concept as follows: ! 1635: .DS ! 1636: .Ls ! 1637: (create \kBbase Concept ! 1638: \h'|\nBu'(if \kA<insertdb MakeForwardInference ! 1639: \h'|\nAu'>fetch MakeBackwardInference)) ! 1640: .Le ! 1641: .DE ! 1642: .LP ! 1643: A similar mechanism is available for attaching demons to individual ! 1644: slots of structures. ! 1645: Other than through matching, the principle way that slots of ! 1646: already created structures get changed is through the PEARL ! 1647: function \fIputpath\fR. ! 1648: For example, if Sam got a raise, making his salary level ! 1649: \fIMedium\fR, we might want to change the \fILevel\fR slot of ! 1650: his Salary structure: ! 1651: .DS ! 1652: (putpath SamsSalary 'Level (getsymbol 'Medium)) ! 1653: .DE ! 1654: If there were facts in the data base (like the fact that Sam is ! 1655: poor) which depended on this fact, we would be interested in ! 1656: monitoring Sam's salary level so that we could fix this up. ! 1657: Of course, a general data dependency mechanism would be much ! 1658: better but if you did not have one, one possible way of ! 1659: accompishing this would be to attach a demon to the Level slot of ! 1660: \fISamsSalary\fR at the time of creation: ! 1661: .DS ! 1662: .Ls ! 1663: (create \kBindividual Salary SamsSalary ! 1664: \h'|\nBu'\kA(Employee Sam) ! 1665: \h'|\nAu'(Level ^ if >putpath (AdjustPoorness =Employee *))) ! 1666: .Le ! 1667: .DE ! 1668: This assumes that \fIAdjustPoorness\fR is a function expecting the ! 1669: name of the person and the new level. ! 1670: .PP ! 1671: Like predicates, a PEARL demon may be either the name of a function ! 1672: to be run with the structure or slot as its argument ! 1673: or it may be a general S-expression which contains any of the ! 1674: special forms which refer to the current structure or slot. ! 1675: Besides the built-in PEARL functions which automatically check for ! 1676: demons with their names on them attached to slots that they touch, ! 1677: there is a facility for user-defined functions to explicitly ! 1678: request that demons on structures or slots that they touch be run. ! 1679: However, this action is not automatic; ! 1680: the involved functions must explicitly run the demons. ! 1681: .NH ! 1682: Implementations ! 1683: .sp 3 ! 1684: .PP ! 1685: The main emphasis of efficiency considerations within PEARL was ! 1686: to allow the user to avoid inefficient algorithms. ! 1687: We also tried to make the code itself as efficient as possible. ! 1688: To make the user interface as friendly as possible, ! 1689: error checking is done whenever it can be done efficiently. ! 1690: As a result of these two principles, PEARL is fast and ! 1691: friendly enough for use as a serious programming language. ! 1692: .sp 3 ! 1693: .PP ! 1694: PEARL was also intended to be portable. ! 1695: It was originally developed on a DEC 20 and moved with no ! 1696: modification to a DEC PDP-10 under UCI Lisp. ! 1697: It was then moved to a VAX-11/780 under Franz Lisp [3] [4] ! 1698: which at that time did not provide a facility for allocating ! 1699: hunks of memory and thus required the lowest level of the ! 1700: implementation to be rewritten using arrays. ! 1701: Since the lowest level of the UCI Lisp version was written in ! 1702: Lisp assembler (LAP) operating on blocks of memory, this new ! 1703: Franz Lisp version was somewhat less efficient. ! 1704: When "hunks" were added to Franz Lisp, we attempted to modify ! 1705: the VAX version to use them. ! 1706: However, since Franz Lisp hunks behave significantly differently ! 1707: in several ways from blocks of memory in UCI Lisp, this was ! 1708: abandoned temporarily. ! 1709: Instead, we used what we learned to redesign the lowest level of ! 1710: the UCI Lisp version of PEARL so that it could be easily moved ! 1711: between UCI Lisp and Franz Lisp and then moved it back to the VAX. ! 1712: .PP ! 1713: We now believe that PEARL could be moved to another Lisp by ! 1714: rewriting about a dozen functions and adding the macros ! 1715: needed to convert from UCI Lisp to the target Lisp. ! 1716: (Only one of these is now machine coded on the PDP-10, ! 1717: a routine for doing address arithmetic. ! 1718: The Franz Lisp version is completely in Lisp.) ! 1719: The primary functions which must be rewritten pertain to creating ! 1720: and accessing hunks of memory and modifying the top level ! 1721: read-eval-print loop. ! 1722: We are currently verifying PEARL's portability by moving it to ! 1723: both MACLisp and Lisp Machine Lisp. ! 1724: .NH ! 1725: Performance ! 1726: .sp 3 ! 1727: .PP ! 1728: As mentioned, PEARL gains much of its speed during fetches from the ! 1729: data base by using a user-assisted hashing mechanism. ! 1730: Here we present some evidence that this mechanism does in ! 1731: fact speed up access to the data base. ! 1732: To test this, we timed the running of a recent version of PAM, ! 1733: a story understanding program [12], which was written using PEARL. ! 1734: For these timings, we used the Franz Lisp version of PEARL. ! 1735: Since the size of PEARL data bases is user-settable, we compared ! 1736: two runs of PAM on a large (23 sentence) story, one using the ! 1737: largest available hash table (see below for details of sizes) ! 1738: and one using the smallest available hash table which is logically ! 1739: equivalent to a linear list. ! 1740: .sp 3 ! 1741: .PP ! 1742: For each run we read in the initial knowledge and program ! 1743: once and then processed the story three times to test the effects ! 1744: of the data base getting fuller. ! 1745: The results are as follows: ! 1746: .DS ! 1747: \h'|\nau' ! 1748: \kaSmall Table \kbLarge Table ! 1749: ! 1750: Load \h'|\nau'68 + 13 \h'|\nbu'30 + 5 ! 1751: ! 1752: Run 1 \h'|\nau'96 + 10 \h'|\nbu'65 + 10 ! 1753: ! 1754: Run 2 \h'|\nau'113 + 11 \h'|\nbu'66 + 9 ! 1755: ! 1756: Run 3 \h'|\nau'129 + 9 \h'|\nbu'65 + 10 ! 1757: .DE ! 1758: .LP ! 1759: Note that while the large hash table was quite stable as the ! 1760: amount of information in it approximately tripled, the small ! 1761: hash table causes the execution times to increase substantially ! 1762: as the data base fills up. ! 1763: .sp 3 ! 1764: .PP ! 1765: In similar comparisons with UCI Lisp on the PDP 10, the results ! 1766: were even more dramatic. ! 1767: Times for the large data base were flat but using a small data base, ! 1768: each run's time was bigger than the previous run by 50% of the first ! 1769: run's time and each run's garbage collection time was bigger ! 1770: than the previous by 100% of the first run's garbage collection time. ! 1771: .DS ! 1772: \kaSmall Table \kbLarge Table ! 1773: ! 1774: Load \h'|\nau'17 + 2 \h'|\nbu'16 + 2 ! 1775: ! 1776: Run 1 \h'|\nau'64 + 13 \h'|\nbu'24 + 2 ! 1777: ! 1778: Run 2 \h'|\nau'92 + 22 \h'|\nbu'24 + 1 ! 1779: ! 1780: Run 3 \h'|\nau'125 + 33 \h'|\nbu'26 + 2 ! 1781: .DE ! 1782: .LP ! 1783: This indicates that PEARL could make large programs running on ! 1784: the PDP10 must faster. ! 1785: It also indicates that although the VAX is a slower machine, ! 1786: with its virtual memory it behaves quite well under what a load ! 1787: that taxes the PDP 10. ! 1788: .sp 3 ! 1789: .PP ! 1790: Another piece of timing we performed is also interesting to those ! 1791: considering moving to VAXes from PDP 10s. ! 1792: All of the above timings were of compiled versions of PEARL on ! 1793: both machines. ! 1794: (The PAM code was not compiled.) ! 1795: Thus, Franz Lisp on the VAX seems to run the same program ! 1796: with 2-2.5 times the CPU time of UCI Lisp on the PDP 10. ! 1797: Since the ratio between the speeds of the processors is estimated ! 1798: at 2.5, compiled Franz Lisp code competes favorably (modulo the ! 1799: processor speed) with compiled UCI Lisp code. ! 1800: However, we also tried running PAM with uncompiled versions ! 1801: of PEARL on both machines. ! 1802: In this case, we found that the Franz Lisp version ran 10 times ! 1803: slower, while the UCI Lisp version ran only 3 times slower. ! 1804: This would seem to imply that either the Franz Lisp interpreter ! 1805: is abnormally slow or that the UCI Lisp interpreter is ! 1806: unusually fast. ! 1807: When the MAC Lisp and Lisp Machine Lisp versions are running, we ! 1808: will explore this further. ! 1809: .sp 3 ! 1810: .PP ! 1811: Although we have not done any extensive profiling of PAM to ! 1812: determine where all the time is spent, we have tried disabling the ! 1813: printing functions while running PAM. ! 1814: Doing this, we discovered that PAM spends about 55% of its time ! 1815: doing input and output. ! 1816: This breaks down to 5% for input, 10% for conversion to list ! 1817: structure from internal PEARL structures and 40% for actual ! 1818: (pretty-)printing by Lisp. ! 1819: .NH ! 1820: Comparison to FRL ! 1821: .sp 3 ! 1822: .PP ! 1823: Of the existing AI languages, PEARL has the most in common with FRL. ! 1824: This is true partly because both languages use several good ideas ! 1825: which have been around in AI for some time. ! 1826: It is also partly true because some of PEARL's features were added ! 1827: in imitation of the example representation language XRL presented ! 1828: in Charniak[2] (which the authors admit is partly in imitation of ! 1829: FRL and KRL). ! 1830: In this section, we discuss some of the ways that PEARL differs ! 1831: from FRL. ! 1832: .sp 3 ! 1833: .PP ! 1834: Like PEARL, FRL is designed for representing slot-filler objects. ! 1835: However, in FRL these objects are modelled more after frames as ! 1836: described by Minsky [7] whereas PEARL's structures lean more ! 1837: toward logical predicates. ! 1838: In particular, frames become \fIactivated\fR or ! 1839: \fItriggered\fR by being instantiated and the data base ! 1840: is simply all the activated frames; ! 1841: there seems to be no distinction between instantiating a ! 1842: frame and adding it to the data base. ! 1843: In contrast to PEARL, frames are not encoded internally but ! 1844: represented as multiple depth association lists and the FRL ! 1845: data base is not hash coded. ! 1846: The FRL manual [10] seems to imply that it is in fact a linked list ! 1847: subject to a sequential search. ! 1848: The idea of separating frames into groups like PEARL's multiple ! 1849: data bases has been recently added as "domains" [6]. ! 1850: .sp 3 ! 1851: .PP ! 1852: Whereas PEARL requires type information on its slots and uses this ! 1853: information to advantage, FRL requires no information on the type ! 1854: or even number of values which will be allowed. ! 1855: This of course allows the user more flexibility but makes it more ! 1856: difficult for FRL to deal efficiently with each slot. ! 1857: .sp 3 ! 1858: .PP ! 1859: In addition to the slot/filler features, FRL uses 6 primary ! 1860: representation techniques to improve the flexibility of frames. ! 1861: These are comments on slots, abstraction through slot inheritance, ! 1862: inherited default values for slots, constraints on slot values, ! 1863: indirection through values in other frames and attached procedures. ! 1864: We look briefly now at each of these. ! 1865: .IP 1) ! 1866: Comments in FRL are attached to slots and are generally used to ! 1867: remember where the value in a slot came from although they could ! 1868: be used for anything. ! 1869: This is a useful feature which in PEARL must be ! 1870: implemented as a separate set of predicates inserted into the data ! 1871: base or as dynamically-added attached procedures. ! 1872: We have not added them to PEARL because we are unsure whether such ! 1873: information should rightly be distinguished from predications ! 1874: about where other pieces of knowledge came from. ! 1875: .IP 2) ! 1876: The notion of inheritance of slots from more abstract objects is ! 1877: quite similar in FRL and PEARL, since this is one of the features ! 1878: PEARL inherited through XRL. ! 1879: The principle difference is that while in PEARL all slots must be ! 1880: predeclared (because of the internal mode of storage), FRL allows ! 1881: the addition of slots at a later time. ! 1882: .IP 3) ! 1883: The notion of default values was similarly inheritted from FRL by PEARL. ! 1884: However, in designing PEARL we wished to more clearly separate the ! 1885: idea of a general piece of knowledge represented by the definition ! 1886: of a type of structure along with its set of defaults from an instance ! 1887: of such a structure. ! 1888: As a result PEARL stores the default values for slots in the special ! 1889: instance of each type of structure called the \fIdefault instance\fR. ! 1890: In contrast, FRL does not make this distinction clear and provides ! 1891: for both a default and a value in a slot of a frame. ! 1892: Apparently a frame may be both an instance and a generalization ! 1893: at the same time. ! 1894: .IP 4) ! 1895: FRL's notion of constraints is significantly stronger and more ! 1896: complex than PEARL's. ! 1897: PEARL provides for predicates on slots but these are only enforced ! 1898: during matching on slots containing variables. ! 1899: FRL on the other hand provides three flavors of constraint with ! 1900: different degrees of restriction. ! 1901: A \fIrequirement\fR is a strong predicate on a slot which must be ! 1902: true of the value in that slot. ! 1903: A \fIpreference\fR is a weaker predicate which may be relaxed. ! 1904: A weaker special case of a preference is a default which simply ! 1905: suggests a specific value which can be easily overridden. ! 1906: .IP 5) ! 1907: A feature of FRL which goes hand-in-hand with the idea of triggered ! 1908: frames (and is thus lacking in PEARL) is that of indirection. ! 1909: This allows a frame to specify constraints on slots of other ! 1910: frames that are currently active when it is triggered. ! 1911: Thus indirection provides what might be considered a "horizontal" ! 1912: version of the vertical notion of default inheritance. ! 1913: .IP 6) ! 1914: Demons and attached procedures are old ideas in AI but FRL ! 1915: introduced a new twist on them which PEARL then took one step ! 1916: further. ! 1917: FRL provides for if-added, if-needed, and if-removed procedures which ! 1918: are attached to slots and rather than being triggered by arbitrary ! 1919: conditions are instead run only in the case of adding, requesting ! 1920: or removing the value of a slot. ! 1921: These attached procedures are enforced by the functions that ! 1922: perform these types of access, thus providing for idiosyncratic ! 1923: forms of inheritance or finding a slot value. ! 1924: In PEARL we extend this idea so that there are a large variety of ! 1925: access functions which may trigger attached procedures (hooks). ! 1926: In addition, these procedures are allowed to affect the actions ! 1927: of the access functions, thus allowing a particular class of ! 1928: objects to tailor the behavior of most of PEARL's functions. ! 1929: Similarly, procedures to tailor the performance of printing and ! 1930: other functions on objects (rather than their slots) are provided ! 1931: by both FRL (via the SELF slot) and by PEARL (via base hooks) ! 1932: In addition, a form of detached procedures ("sentinels") have ! 1933: recently been added to FRL [6] in which the triggering condition ! 1934: is the activation of a group of frames. ! 1935: .sp 3 ! 1936: .PP ! 1937: In contrast to more ambitious knowledge representation languages, ! 1938: FRL and PEARL are similar in their fairly restricted matching ! 1939: procedures which are essentially slot-by-slot matches with no ! 1940: provision for matching to a degree or forcing a match via mapping ! 1941: as in MERLIN [8]. ! 1942: .sp 3 ! 1943: .PP ! 1944: Finally, there are two features of hierarchical representations ! 1945: which FRL provides but which are not yet provided by PEARL. ! 1946: The principal one is the ability to store multiple views of an object ! 1947: thus allowing a frame to inherit slots from several other frames. ! 1948: The second one is the ability to move an object down the hierarchy, ! 1949: thus providing the dynamic ability to further specify a previously ! 1950: general frame based on new information. ! 1951: Both of these are in the works since we have encountered a need for them. ! 1952: .NH ! 1953: Comparison to KRL ! 1954: .sp 3 ! 1955: .PP ! 1956: .bp ! 1957: .NH ! 1958: References ! 1959: .sp 2 ! 1960: .IP [1] ! 1961: Bobrow, D. G., and Winograd, T. "An Overview of KRL, a Knowledge ! 1962: Representation Language." ! 1963: \fICognitive Science\fR 1:1 (1977). ! 1964: .IP [2] ! 1965: Charniak, E., Riesbeck, C. K., and McDermott, D. V. ! 1966: \fIArtificial Intelligence Programming\fR. Hilldale, New Jersey: ! 1967: Lawrence Erlbaum Associates, 1980. ! 1968: .IP [3] ! 1969: Fateman, R., "Views on Transportability of Lisp and Lisp-based Systems", ! 1970: in \fIProc. of the 1981 ACM Symposium on Symbolic and Algebraic ! 1971: Computation\fR p 137-141, (ACM order no 505810), 1981. ! 1972: .IP [4] ! 1973: Foderaro, J. K., and Sklower, K. L. ! 1974: \fIThe Franz Lisp Manual\fR in \fIBerkeley UNIX Reference Manual\fR, ! 1975: Vol. 2c., Computer Systems Research Group, Computer Science Div. ! 1976: EECS Dept., University of California, September, 1981 ! 1977: .IP [5] ! 1978: Greiner, R., and Lenat, D. "A Representation Language Language." ! 1979: In \fIProc. First NCAI\fR. Stanford, CA, August, 1980, ! 1980: 165-169. ! 1981: .IP [6] ! 1982: ?????, ?. "Extended Features of FRL" ?????, reproduced in forthcoming ! 1983: edition of [4], 1982. ! 1984: .IP [7] ! 1985: Minsky, M. "A Framework for Representing Knowledge" in P. H. ! 1986: WInston (Ed.) \fIThe Psychology of Computer Vision\fR, ! 1987: New York: McGraw-Hill, 1975. ! 1988: .IP [8] ! 1989: Moore, J., and Newell, A. "How Can MERLIN Understand?" in L. Gregg ! 1990: (Ed.), \fIKnowledge and Cognition\fR, Lawrence Erlbaum Associates, 1973. ! 1991: .IP [9] ! 1992: Roberts, R. B., and Goldstein, I. P. ! 1993: "NUDGE, A Knowledge-Based Scheduling Program." ! 1994: In \fIProc. IJCAI-77\fR. Cambridge, MA, August, 1977, 257-263. ! 1995: .IP [10] ! 1996: Roberts R. B., and Goldstein, I. P. ! 1997: \fIThe FRL Manual\fR, MIT AI Memo, September, 1977, reproduced in ! 1998: forthcoming edition of [4], 1982. ! 1999: .IP [11] ! 2000: Schank, R. \fIConceptual Information Processing\fR. Amsterdam: North Holland, ! 2001: 1975. ! 2002: .IP [12] ! 2003: Wilensky, R. "Understanding Goal-Based Stories", ! 2004: Technical Report 140, Computer Science Department, ! 2005: Yale University, New Haven, CT, September 1978. ! 2006: .IP [13] ! 2007: Wilensky, R. ! 2008: "Meta-Planning: Representing and Using Knowledge about Planning in Problem ! 2009: Solving and Natural Language Understanding." ! 2010: \fICognitive Science\fR 5:3 (1981). ! 2011: .rm CF ! 2012: .bp 0 ! 2013: .sp 14 ! 2014: .B ! 2015: .LG ! 2016: .ce ! 2017: Table Of Contents ! 2018: .SM ! 2019: .sp 2 ! 2020: .DS ! 2021: 1. Introduction \ka 1 ! 2022: 2. An Overview and Sample Application Of PEARL \h'|\nau' 2 ! 2023: 3. How Fast Is PEARL? \h'|\nau' 6 ! 2024: 4. Objects and Structures \h'|\nau' 7 ! 2025: 5. Data Base Facilities \h'|\nau'11 ! 2026: 6. Fetching \h'|\nau'17 ! 2027: 7. Predicates and Matching \h'|\nau'18 ! 2028: 8. Variables \h'|\nau'21 ! 2029: 9. Demons \h'|\nau'23 ! 2030: 10. Implementations \h'|\nau'24 ! 2031: 11. Performance \h'|\nau'25 ! 2032: 12. Comparison to FRL \h'|\nau'26 ! 2033: 13. Comparison to KRL \h'|\nau'29 ! 2034: 14. References \h'|\nau'31 ! 2035: .DE ! 2036: .bp 0 ! 2037: .sp 14 ! 2038: .SH ! 2039: Acknowledgements ! 2040: .PP ! 2041: PEARL was originally a joint project of Joe Faletti and Mike ! 2042: Deering (now at the Fairchild AI Lab in Palo Alto) aimed at ! 2043: redesigning, extending and completely rewriting an earlier ! 2044: package designed and written by Mike. ! 2045: PEARL owes many ideas and much of its success to Mike who ! 2046: has been involved in all design decisions. ! 2047: In particular, the hashing scheme which is responsible for ! 2048: much of PEARL's efficiency was originally his idea. ! 2049: .PP ! 2050: The initial move of PEARL to the VAX from which we learned enough ! 2051: to make the second one easier was accomplished by Mike Deering ! 2052: and Doug Lanam (now at the Hewlett Packard AI Lab in Palo Alto). ! 2053: The move was made significantly easier by Doug's UCI Lisp ! 2054: compatibility package for Franz Lisp. ! 2055: .PP ! 2056: The authors wish to thank Mike and Doug for their contributions. ! 2057: We also wish to thank the members of the Berkeley AI Research ! 2058: group (BAIR) who have used PEARL during its development and made ! 2059: many valuable suggestions based on active experience in its use.
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.