CS470/570  Artificial Intelligence

Program #3: It's only logical!
(a.k.a.,  knowledge-based agents built on FOPL in Prolog)

Overview:  Description: oggle.jpg

Now that we have a fundamental understanding of how logics work and, specifically, how First-Order Predicate Logic (FOPL, the book used FOL) works, we need to get our hands dirty to practice and deepen that understanding somewhat. In theory, we'd love to build our own logical reasoning system in Python...that would be really cool, and isn't actually all that hard for a basic version. But there are a lot of details involved, and we're really less interested in implementing a logic programming environment, and more interested in seeing how such an environment could allow "reasoning" to happen.

Fortunately, there is a whole language that is based, in essence, on an implementation of a backward-chaining logical proof processes: Prolog. It works for Propositional Logic (relatively easy), but also works for FOL with universal quantification and all the bells and whistles...so it's just what we need. Our aim, therefore, is to:

  1. express a simple world of facts and inference rules in FOL...and then translate this knowledge into a Prolog program.
  2. and then use the Prolog solver to answer some questions about the situation, deducing various conclusions not directly present as base facts.
  3. Analyze the problem-solving behavior of the Prolog solver system a bit, to make the connection between what we've been working through in lecture/book, and what the Prolog solver is doing.

The advantage of using an existing logic solver (i.e., Prolog in this case) is that we can focus on the logic and the inferencing. The disadvantage is that -- because Prolog is doing a bunch of the work for us -- we risk losing track of the actual logic solving process that is going on within Prolog to arrive at the answers. We will try to address this disadvantage by taking a look under the hood as part of the write-up questions.

The Problem:

It would be lovely to use Prolog to implement a "tour guide" in our dangerous Wumpus cave, i.e., an agent that we can ask questions about the board as we go along (e.g. Is square [x,y] safe?). This is a little bit harder than I'd like, however, given that we are Prolog beginners at this point (anyone that wants to tackle it as E.C. is welcome to).

Our focus, therefore, will be on solving a very straightforward problem centered around two problem domains introduced in the book:

These problems are dead simple but, as you might expect, this will take some exploration of Prolog and careful thinking about the FOPL "knowledge" that you give it. It will definitely take some time to get your head around what "programming" means in a declarative world! Plus there is your analysis and write-up of what you've done, where you investigate how the logic solver is doing its work, and why it is finding the solutions that it finds. So, as usual, you'll want to start early and plan your time wisely!

The Assignment:

As indicated above, there are two parts to this assignment. The order in which you tackle them doesn't really matter; they are more or less independent and neither one is really a "warm-up" for the other. Part 1 is like 8 lines of code, but requires more thinking. Part 2 has lots of rules/facts but they are all pretty straightforward.

Part1: Math based on the Peano Postulates. Read section 8.3.3 carefully. It's pretty cool: it says that given a definition of what a natural number is and a successor function, you can define most of mathematics. So let's do a little of that: Let's take FOPL definitions of natural numbers and a successor function, and use them to develop working definitions of addition, multiplication and exponentiation, just like the book promises is possible. Here are detailed constraints:

Part 2: At play in the forest of family trees. Read section 8.3.2 again to refresh your memory. The concept is pretty straightforward: we want to encode all of our knowledge about how kinship relationship are defined: fathers, mothers, in-laws, etc. Then, separately and as often as we like, we can give our system some set of information that is known about a particular family...maybe it's complete, maybe it's partial, it doesn't matter. Finally, we can then query our system to spit out (via FOL inference) information about the declared family information. Here are the detailed constraints:

Here is a nice little output file showing my kinship solution code hard at work.

To get you up and going fast, here is a little insta-primer I made on how to get going with Prolog.

Your write-up: 

In addition to your code and solution print-outs, you'll need to provide a nice write-up of your solution.  Your write-up should be professionally neat and must include:

  1. Using correct and exact FOL syntax, give your FOL rules that encode the knowledge for (a) the Peano problem domain; and (b) the Kinship domain. The listing must include exactly the FOL definitions that drive the Prolog code that you produced. For each rule you write down, start by giving the "plain English" translation of what you are attempting to encode, as well as explaining any thoughts or tricky points associated with your encoding.
  2. In a step-by-step fashion, walk me through the how Prolog goes about finding the answer to "ancestor(Who, eugenie). Your exposition should be clear and written/formatted as an explanatory technical narrative, i.e., like you're writing a textbook or paper and explaining what's going on at each step to your readers. Obviously, your explanation should demonstrate your keen understanding of the inference algorithm being used.
  3. Isn't it weird how some queries (e.g. brother(Charles,X) ) in my sample output seem to have "duplicate" answers, listing the correct answers *twice*? I wonder why that's happening for some queries but not others? Strange. Investigate this and explain very clearly what exactly is going on.

To turn in:

A professional hardcopy packet with the following items in exactly this order:

  1. Cover sheet:  Name, course, assignment title, date
  2. Your write-up, typed up, cleanly formatted.
  3. Printout of your clearly documented code including (clearly labeled) Part 1 and Part2. Important: For each of your predicates, place the FOL version of is as a comment immediately above the predicate. Separate predicate groups (group=several rules for same predicate) by a line of whitespace for readability.
  4. Printout of your program running the output from the specified queries on the dynamically assigned math problems.
  5. Printout of your program running the output of the specified queries on the dynamically assigned family tree problem. Both the Math and Tree dynamic problems will be linked here right here before the due date.