WORCESTER POLYTECHNIC INSTITUTE
Computer Science DepartmentCS534 - Artificial Intelligence
Wed 6:00-9:00Prof. David C. Brown, Fuller Lab 131, (508) 831-5618, dcb@cs.wpi.edu
http://cs.wpi.edu/~dcb/courses/CS534/
PROJECT 3 - An ATN Interpreter
You are to write and demonstrate an Augmented Recursive Transition Network Interpreter for "understanding" natural language input. The interpreter will take the description of a grammar, and a dictionary, and will execute actions that will produce something that represents the meaning of the sentence. It can produce either a list, a command (e.g., an fget) or a partially filled-in frame (your choice). We are not concerned with building a syntactic description of the sentence.
The interpreter must be independent of the actual grammar and dictionary used. It would be ideal if both of those can be input from files. Sentences are input from the user directly or via a file (for convenience in testing and demonstration).
The network consists of Labeled States connected by Labeled Directed Arcs. The labels on the states can be used to indicate to the human reader of the diagram what has been recognized up to that point in the grammar. Arcs can be traversed if the next thing in the sentence is what is indicated by the label of the arc. A Label can be a word, a word category (e.g., Noun), or the name of a sub-network (e.g., NounPhrase). Each sub-network (i.e., subnet) corresponds to a Non-Terminal in the grammar. An arc can succeed or fail. If a subnet name appears on an arc then that network is used to determine whether the arc can be traversed. Special arcs can be used that cause a state-to-state transition independent of the input and will always succeed.
Recognition takes place in a net when a distinguished state (EndOfNet) is reached. Complete recognition of an input requires recognition by the top-most net, with no more words left in the input.
This is an example of an ATN diagram:
As transition across an arc can depend on the successful traversal of a subnet you will need a stacking mechanism to keep track of the parsing situation. If your programming language allows recursion you may be able to have the language take care of the stack.
As more than one arc can emerge from a state it is necessary to pick one to follow when you leave a state. This is done by considering the arcs as ordered, and selecting them in order. As an attempt to follow an arc may fail, you will have to keep track, for every state, of the arcs that have still to be tried. At failure the ATN backs up to the last choice-point and selects the next untried arc.
To be more specific, each arc is labeled by one of the following list.
CAT <category> <test> <post-action(s)> <destination> WRD <word> <test> <post-action(s)> <destination> MEM <list> <test> <post-action(s)> <destination> JUMP <destination> <test> <post-action(s)> PUSH <state> <test> <pre-action(s)> <post-action(s)> <destination> POP <form> <test>The first element is the arc type. The second depends on the type. The third is a predicate that must be true (in addition to any other conditions) in order for the arc to be traversed. The action(s) can be any actions that you like. In a full-blown ATN they generally manipulate the contents of a set of registers. If you like you can use some global variables with pre-defined names and/or you can use the slots of one or more frames. The post-actions occur just prior to reaching the destination state. Each arc also includes the name of the destination state.
The exact declaration format for each arc and state is up to you. However, the arcs should include all the information specified. Please use the labels CAT, WRD, etc., and not some other set obtained from elsewhere.
The CAT arc is followed (i.e., traversed) if the current input word is of the right category. A WRD arc specifies the exact word that must be matched, while the MEM arc specifies that the input must be a "member" of the specified "list" of words (e.g., {a, the} ). All three advance the input pointer. Note that it is traditional to refer to the current item in the input (i.e., the target of the input pointer) as "*".
The JUMP arc forces a successful transition without moving the input pointer. The PUSH arc starts processing at the network start state named. The pre-action(s) are done prior to transfer to the new net; the post-actions after successful completion of that net. A POP returns from a subnet back to the PUSH arc that "called" it. A POP arc does not have any destination state. A state with a single POP arc leaving it is the distinguished state that marks the end of a net. The "form", which can be anything you want it to be, is returned to the push arc as a result which can then be acted upon by the post-action(s). If you like you can implement this without this return mechanism, returning results using global variables.
Note that as backtracking can occur, the state of the target data-structures (i.e., the semantics of the sentence) must be included in each recorded state situation. These situations are recorded on a stack. If you do not include the data-structures you will have to "undo" actions! That is, any frames that you use to keep track of the parse should be kept separately from the main frame hierarchy, and only attached to it after a completely successful parse.
You might want to have a dictionary accessing function that can check if a certain word has a certain feature. For example, (GetFeature Number *) might return "Plural". The predicate (CheckFeature Number * Plural) might return "true". Other functions or predicates can be invented as necessary. The exact form of the dictionary is up to you. It should probably include the Category (e.g., Noun), the Number (e.g., Plural), and the Root form (e.g., Walk, as opposed to Walking). It could also contain Case information for verbs (e.g., Agent + Object + Instrument).
The ATN is to be specified in some notation and read in, thus "setting up" a network that the ATN interpreter can act on. Clearly demonstrate the action of your interpreter with some test grammars, and some test sentences. Make sure you print the semantic representation which is the result of your parse, however simple it may be.
The keys to the implementation are the proper representation of the current condition of each node in the ATN, and the handling of the recursive implementation of the ATN interpreter. Consider the main function as being: given a node, traverse an arc. This can be used recursively. The node's representation allows the state of the parse at a node to be recorded at that node.
An implementation of a problem that is `similar', such as might be found in a textbook, will not be accepted.