-------------------------------------------------------------------- INTRO -------------------------------------------------------------------- This problem set has a lot of auxiliary code. DON'T PANIC. You don't need to understand the implementation of the rules system. You do need to have an idea of how to use it. Below, you'll find a sketch of the system; combined with the example rule executions, you should get a sufficiently good sense of how the system works to solve the problem set questions. If you want a more detailed picture, feel free to grunge through the code. Our spies out in the Real World tell us the experience you gain by using large systems via abstractions defining their interfaces will help you tremendously throughout your career. "It's for your own good." -------------------------------------------------------------------- SKETCH OF RULES SYSTEM -------------------------------------------------------------------- Patterns in the rule system are semantically very similar to patterns in the matcher you wrote for ps0, though the syntax is a little different A pattern is a list of atoms or variables. A variable is a symbol whose first character is a ?. An atom is any other symbol. (In fact, other primitive Scheme types work as atoms, but you won't be required to use them.) For example: (?person was a meanie) would match against the assertion: (stalin was a meanie) with the expected binding ?person to the symbol stalin. The system supports structured patterns and assertions, using standard scheme syntax. See the examples for help. -- A rule is a list of the form ( IF ... AND-IF THEN ... ADD ... DELETE ... ) The must be first. The IF section must follow immediately afterwards, then the AND-IF, then THEN. ADD and DELETE can be in any order. must be a symbol; it identifies the rule. Antecedents are patterns. They must *all* be matched against the assertions database. If the list is empty, the rule will always pass this test. If the antecedent test wins, we go on to the and-if test. If an AND-IF section is present, must evaluate to true (against the variable bindings from the antecedents). The variables must be quoted in this expression. See the "structured" example in the examples file for details. This sounds more complicated than it is. It's useful for testing properties of assertions in the database that can't be nicely represented using the pattern language; in effect, it extends your testing capabilities to all Scheme programs. Consequents have the same form as patterns. They specify what assertions should be added to the database if the rule fires. The actual assertions added in have the structure of the specified consequents, with bindings substituted in for variables. Deletion works similarly: matching assertions are deleted. To recap, a rule is *triggered* if the following tests all succeed: - All antecedents (if any) are matched - The expression from the AND-IF evaluates to true, if it's there - One assertion that would be added by the rule if it fired isn't in the database - that is, there's something to add OR One assertion that would be deleted by the rule if it fired IS in the database - that is, there's something to delete Note that the rules language typically permits many different expressions of rules that get the same result (e.g. by using an AND-IF clause with an or, or instead having one rule for each branch of the disjunction). Pick whatever one you like; just make sure that you abide by all constraints regarding the number of rules you're allowed. -- To load rules into the system, you can: - read-k-file to read in rules from a "knowledge" file. calls remember-rule on each rule in order. This may clobber any other rules you've added, so do it before adding rules of your own. - define symbols containing the content of your rules and use remember-rule to remember them; this is often how your solutions will be loaded. remember-rule adds the given rule to the end of the rule list. Loaded rules will therefore be stored in the order that they were given. To look at the currently loaded list of rules, evaluate (get-rules) You probably want to pretty-print this. -- The forward-chaining rule system fires rules in the following way. It searches down the rule-list *in order* and determines what rules can be triggered by the criteria above. It then fires (executes) the *first* rule that it finds on the *first* assertion that the rule matches. This means it adds/deletes the assertions specified by the patterns in the rule. The forward chainer steps until either the maximum number of steps is exceeded, no rules trigger, or the assertion (STOP) occurs in the database. The backward chainer steps until the desired assertion matches a pattern in the database. If you want to reorder the rules, use the set-rule-order procedure. This procedure takes a list of rule names. It puts the given rules in the given order at the beginning of the list, leaving unspecified rules at the end in their previous order. Rules may be added multiple times. For example, if rules R1, R2, R3, R4, R5 were in the database in that order, the call (set-rule-order 'R5 'R3) changes the rule order to R5 R3 R1 R2 R4 This is VERY IMPORTANT, as the order of rules absolutely affects the behavior of a rule system. Once rules are defined, you can rewrite individual rules by simply remember-rule ing them. This is what you are expected to do for problem 4; the backtweak procedure must rewrite those rules that need to be rewritten, by calling remember-rule, then it must reorder rules as necessary via set-rule-order. --------------------------------------------------------------------- ADVICE ON THE PSET --------------------------------------------------------------------- - Start by understanding the given examples. If you can't comfortably create rule sets and execute a forward or backward chainer on them, you will not be able to do the problems. - Before attempting to solve each problem, load the relevant rules, grab a set of assertions from the public test cases (typically named case1, case2, etc), and see what the rules do with those assertions by running the chainer yourself. Then see if you understand the issue the problem is getting at. Make sure that *t:silent* is set to #f so you can watch the chainer print out the steps it takes. - Test modified rules in your own Scheme files; don't only rely on test-file. - Problem 2: use the STOP assertion to terminate when appropriate. Remember to load your rules from problem 1 here. - Problem 3: fix-rules is a list of assertions. For testing, load it via (apply remember-rules fix-rules), after reading in prodpassenger.k. You may find this problem a bit tricky; make sure to move on if you feel you're getting stuck. - Problem 4: Your procedure (backtweak) should have the form: (define (backtweak) (begin (remember-rules ... ) (set-rule-order ... ) ) ) Also remember, consistent with the notes, that all cases have their categorization already completed. - Problems 5-11: Look carefully at the search procedure, as well as the search routines you've been given. Test your search procedures on simple graphs. Look in us.scm for the test graph for these problems.