CS 4600
Introduction to Intelligent Systems
Project #6
First Order Logic

Numbers

Due: November 5, 2003 23:59:59 EST
Please email your code and explanations to Patrick Yaner with the subject line "cs4600 project #6". Also, be certain to include your name in your message.

The extra credit assignment is worth 5 points added to your final grade (that's about 16.7 points on the midterm).

Why?

You know why, don't you?

Well, in addition to that, this assignment is designed to let you think about a simple procedural approach to dealing with first order logic, and as a side-effect will actually help you to prepare for one of the other projects to come.

You will be asked to implement forall, thereexists and thereexists! as macros(!) to work in a simple domain or three, and to propose extensions to make them work in other domains.

Naturally, all of this will be done in LISP, because macros and first-class functions make this much, much, much simpler to do (and because I like LISP).

Read everything below carefully!

Domains

Our logical sentences have to apply to some domain, so here we are going to define and work with some domains:

In utils.lisp you will find the function get-lisp-symbols. It returns all the symbols defined at any particular time in a running LISP process. You have to write the functions for the other two domains:

First Order Constructs

You're also going to write a few first order logic "functions":

...which have the usual meanings of for all, there exists, and there exists exactly one.

Proving First Order Sentences

In utils.lisp you will find two sets of definitions. The first is get-lisp-symbols. As noted above, it returns a bunch of LISP symbols. The second set includes the prove macro. It takes a first-order logic expression to be evaluated and a domain of interest and evaluates that expression in the context of that domain. For example, it can be invoked like this:

  ;; Prove: There is some integer between 1 and 10 that is greater
  ;; than five
  (prove (thereexists x (> x 5)) (integers 1 10))
     ---> T (or at least some non-NIL value)

  ;; Prove: All numbers between 1 and 10 are equal
  (prove (forall x (forall y (= x y))) (integers 1 10))
     ---> NIL

  ;; Prove: All numbers between 1 and 1 are equal
  (prove (forall x (forall y (= x y))) (integers 1 1))
     ---> T (or at least some non-NIL value)

  ;; Prove: In LISP, there exists something that is a list
  ;;   (in our domain, that's like saying there exists something
  ;;    called a list that some symbol is bound to)
  (prove (thereexists x (and (boundp x) (listp (eval x)))) (get-lisp-symbols))
     ---> T (or at least some non-NIL value)

Important: Notice that there are no quotes (' or "") above. For reasons of elegance, I want you to write each of the three constructs as macros, not as functions. You can find an example of using defmacro in utils.lisp for this project and you can find many other examples in utils.lisp from Project 2. A great deal of information and documentation is available on LISP macros online and/or in Steele's book on Common Lisp. I have a local copy online at: http://www.cc.gatech.edu/~isbell/references/lisp/. One other note: my implementations are just a few lines long; however, they do use a call to gensym, so you might want to be comfortable with that as well. I believe Steele goes over why gensyms are useful in macros in the sections on macros. There's also an example in utils.lisp for Project 2.

Also notice that because get-lisp-symbols returns symbols instead of actual objects, you have to use eval on the symbols that are returned in order to determine the actual LISP object they represent. Because some of the symbols you will get will be unbound to any object, you should also be sure that you test them with boundp (if you cared about functions you'd use fboundp, but we don't here), as in the example above. BTW, this is a lesson about domains: you have to think about them very carefully. For example, what if more than one symbol refers to the same object? Is that possible here? Does that affect the meaning of the sentences below?

Finally, this also means that if you write your own implies and/or doubleimplies that you want to implement them as macros, not functions. Why, you ask? Well, for the same reason that if, and, and or are implemented as macros.

What to Turn In

You must email the TA three attachments.

  1. The first contains a file with all of the functions/macros described above:

    ...along with any helper code you need (for example, you'll probably need to implement implies and doubleimplies macros). As always, any additional functions or variables you use should have your-gtaccount appended to them, except that in this case you may use implies and double-implies without the suffix (just for the sake of readability). Please name this attachment yourgtaccount.lisp.

  2. The second attachment contains a file that shows your translation of the following English sentences into LISP expressions that you can evaluate, and your actual evaluation of them using the code you have written. Just copy and paste from your LISP session. Please name this attachment yourgtaccount.txt1. Include your name and gt account up top.

    1. Every integer between 1 and 10 is odd.
    2. Among the integers between 1 and 10 there is an odd number.
    3. At least one of the prime numbers between 1 and 10 is even.
    4. Every integer between 1 and 10 is at least as large as some other number between 1 and 10.
    5. There is a smallest number between 1 and 10.
    6. In LISP, all integers are numbers.
    7. In LISP, a cons cell is also a list.
    8. In fact, cons and lists are equivalent.
    9. In LISP, there is an object that is both an atom and a list.
    10. Actually, there is only one object that is both an atom and a list.

    It turns out that LISP already has built in many of the functions you'll need. For example, (integerp obj) return t/nil if obj is/isn't an integer. There's also oddp, consp, numberp, listp, atom (as opposed to atomp) and probably a my-code-is-correctp as well.

  3. The third attachment contains a text file answering these two questions:

    1. Each of the domains you have implemented is finite. In particular, you have created functions that represent the universe as a list. Explain what modifications you'd have to make to prove and your first-order constructs in order to represent infinite domains. For simplicity's sake, let's say that any domain you'd be asked to represent would have a conventional starting point. As an example, how would you handle the domain "all positive integers" with the "first" element being zero? Assume for the purpose of this discussion that LISP is a mathematically perfect abstraction, and so has infinite memory and can represent any number without generating an overflow error.

    2. Given that you could represent an infinite domain, would your modifications actually work in practice? Would you be able to answer first-order questions about infinite domains with any hope of your code actually returning? Give an example of a true sentence where your procedural approach would fail. How would you have to deal with this issue?

    Please name this attachment yourgtaccount.txt2. Include your name and gt account up top.