CS 396
Logic Programming Challenge
Points: 60 pts
Rules: Individual Effort. You may specifically NOT use solutions found on the internet, texts or elsewhere; such plagiarism will be severely santioned.

Overview:

In this exercise, we will explore the logic programming paradigm. We'll start with a little bit of light "programming" in Prolog to get the idea.

Objectives:

Preamble: Getting familiar with Prolog.

Before we try to implement any portion of a logic programming system, we need to get familiar with what "logic programming" is all about. The best way to do this is to do a couple of little toy problems using a real Prolog interpreter. We will be using SWI-Prolog, so you'll want to install it on your favorite machine. Visit the SWI prolog download page; looks like the latest stable release is currently 7.2, though for if you have the lastest MacOS, you'll need to get dev version 7.3. Make sure you read through the installation notes that come with it. In particular, it usually installs in /opt/local/bin or some similar directory; you'll probably want to add this to your local PATH to simplify using it.

Either way, you edit with your favorite text editor, then load (called "consult" in prolog) the source into the interpreter for testing. Edit and repeat as necessary. For details, here are some resources:

Part 1: Doing simple programming in Prolog.

Programming is strange in prolog: you have to phrase your desires as a predicate; "proving" that the predicate is true amounts to showing you an answer to the function call. So basically thinks of a predicate as "Is it true that the answer to this question with these arguments is X", where X is a variable. Prolog then does the proof...if it was able to prove it, it answers "Yes...with the variable X bound to this value". We'll just do a couple of these to give you the idea.

Just have to support two little predicates, about five lines of code total..

A simple math function called "multn"; just multiplies together the two positive integer args.  The format is:

multn(int1,int2,result)

This is a very simple function just to give you some practice with the very basic ideas of prolog.  To make this interesting, you must solve this problem in recursive fashion, and may NOT use the multiplication operation itself in the solution!   So I'll be looking for a base case plus one other predicate. You may assume that only non-negative integer args are passed in.  Some examples:

?- multn(5,3,OUT).

OUT = 15


?- multn(20,56,OUT).

OUT = 1120

A character deleter predicate called "ndelete";deletes regularly-spaced elements from a list.. The format is: ndelete(n, [inlist],[resultlist])

So this predicate deletes every nth element from the input list. As this is a predicate that you want to prove, the first two args are essentially the input arguments, and the third is the output argument. Some examples:

4 ?- ndelete(2,[a,b,c,d,e,f,g,h,y,t,r],OUT).
OUT = [a, c, e, g, y, r] .

5 ?- ndelete(1,[a,b,c,d,f],OUT).
OUT = [] .

6 ?- ndelete(4,[a,b,c,d,e,f,g,h,i],OUT).
OUT = [a, b, c, e, f, g, i] .

Part 2: Social Network Explorer

Ok, now that we have gotten our feet wet with how Prolog work in general, let's just use the power of this language to solve a little problem for us:

Imagine that one day, a solar flare takes out all the cell towers (gasp!) and suddenly there are no cell phones, no texting and no internet! Oh the horror! The problem is that Dr. D desperately needs to reach Rachel, a student, to let her know that she's won the $1M Brilliance Award...but that she needs to show up to claim it by 5pm that day, or it goes to the runner-up.

So Dr. D sees Doug in the hallway and asks him to let Rachel know to come by ASAP. Doug says that he'll try to get the message to Rachel somehow. In particular, assume the following social network of connections between students:

So, what we want to write here is essentially a social network explorer to answer the burning question: does Rachel get the message and take home the big bucks? Plus any other "who talks to who problem we might throw at it!

Specifically, write a Prolog program that tackles this problem for you. For any two people A and B, it should output a path that the message could get from A to B; by hitting the ' ; ' repeatedly, you should then be able to get it to show you --- one after the other --- all possible paths that the message could get through by. In particular, your solution should provide the following top level functor:

connect(A, B) -- This functor takes in two arguments and tries to find (think: prove) a path between A and B.

in addition, all of the above facts must be represented by the following functor:

link(Person, Person) -- This means that the fact that "Doug talks to Luther" should become the fact link(doug,luther). You must use the link(a,b) functor to represent your facts; my grading program will count on it!

Important: You may use the "link" functor **only** as a fact in your code, and not as a rule statement. To test your code, my testing program starts by loading your code file, then *deleting* all link functors from the fact base to make sure we start clean. Then it loads my own link statements (my own social network) and tests your code with it. Therefore, you should only use link for the facts in your program...if I wipe them all out and load my own, nothing bad will happen. So you should have nothing that looks like "link(A,B) :- something" in your code!

I'll give you a hint on this, which also solves a problem that you need to solve anyway. Just include the following rule in your program:

knows(A,B) :- link(A,B); link(B,A).

So this says I can prove that A knows (talks to, is directly connected to) B if you have either a link(A,B) or a link(B,A) fact in your DB. In other words, it doesn't matter who is linked to who (the order of the people in the link), those people know each other....the connection is bi-directional. And now, in the rest of your code to solve the problem, you just use the knows functor.

So, with the fact base given above, I should be able to do:

27 ?- connect(dillon, colter).
[dillon,colter]
true ;
[dillon,luther,doug,kyle,zach,charles,colter]
true ;
[dillon,luther,doug,kyle,colter]
true ;
[dillon,luther,doug,kyle,garrett,charles,colter]
true ;
[dillon,brandon,colter]
true ;
false.
See what I mean? I asked it to prove a connection between Dillon and Colter. And it immediately found one: there is a simple fact that Dillon talks directly to Colter. Okay, but then I hit the ';' and it restarted the proof and showed me the next possible connection between the two. It kept showing me connections as I hit the ';' repeatedly...until it had exhausted all options and returned false.

Now use your program to answer the following questions:

  1. Given the meetings listed above, show your program calculating all possible paths that the message could get from Doug to Rachel. A path should just be a list of people starting with Doug. So my program puts out answers that looks like: [doug,luther,dillon,colter,charles,garrett,rachel]. (Hint: there are 11 possible paths )
  2. Now, assume that there was a miscommunication: Zach may have met Charles, but he didn't tell him anything...that link is broken! Now: will Rachel still get the message?...and, if so, how many possible ways are there now? Show your program working this out.

Note that the *order* in which your program produces the solutions (as you hit semi-colon) doesn't matter...so long as it finds all possible paths.

Tips for tackling this challenge. Because Prolog is doing all the real work for you, the entire meat of the solution for this part is basically just TWO LINES LONG!! Really, no kidding: there I have another two little helpers to make it nice, but just one functor (with a base case and a recursive case) does the real work. That's the power of logic/declarative programming! Wow! Note I do have a bunch of facts, of course, reflecting who met who, which I'm not counting here...I'm just talking about the inference rules. The trick is to just see this as a network traversal problem: people are the "nodes" and whether or not they meet is an "arc" between those nodes. Given that, you're program just has to "explore" its way through this network, exploring all possible ways from the starting point A to the finish B. Or, to put it in Prolog terms, proving that a path between A and B exists.

Ok, so your "facts" are all in the form of "talks(personA, personB)". That's easy. Then you have the one key functor, nice and recursive, which has to express:

Base case: A communication targeted at person T -- and which is currently at some person N, having traversed some previous path P -- is proven if N is the same as T. Then I'm done! And the answer I return is just: the current person N stuck onto the front of the previous chain of people P.

Recursive case: communication currently at some person N, having followed a chain of people P so far, and targeted at some person T, could also succeed if it can be shown that person N met person N1, and if (recursion!) a connection from N1 to T can be shown to succeed.

So wow, I've just about given it all away! All you have to do is turn that into Prolog rules! A few pointers:

Self-Testing your results.

MANDATORY pre-submission self-testing: The worst thing in the world is to have spent hours on your program, only to have it fail in testing because you mis-named a functor, etc. Here is a little testing script called testme.pl that functions in way similar to my grading program. You just place both this script and your program into the same directory, then get Prolog running (make sure to do pwd. in prolog to see what it thinks its working directory is. cd('path'). your way to the right place as needed). Edit the testme.pl and put in your code's filename for sfile. Save. Then just go into prolog and type "[testme]." Should load your code and test run all the functors on the test cases given above. Here is the output I get.

To Turn In:

  1. Hardcopy packet: 
    1. cover sheet,
    2. Printout of your program running through the mandatory "testme.pl" self-testing program above.
    3. Printout of your code in solving the two network problems given above,
    4. brief discussion of how the key functors in your code work for each part,
    5. and hardcopy of the code itself. 
    Collated and stapled in that order, please!
  2. Electronic Submission of your code on BBlearn.