CISC-280 Homework #5: Due October 18

All of the code discussed here can be found in $CLASSHOME/hw5/hw5.scm or from the web link.

Symbolic Differentiation
Remember our symbolic differentiation program, from Chapter 2.3.2? Extend the program to handle exponentiation. You will remember that the differentiation rule for exponents is:

For example, dx3/dx = 3x2(dx/dx) = 3x2

You will need to add a new clause to the deriv procedure, and define the appropriate abstract data operations exponent?, base, exponent, and make-exponentiation. Use the symbol ** to indicate exponentiation. So we would write 3x2 as '(* 3 (** x 2)). Build in simplification rules that anything raised to the power 0 is 1, and anything raised to the power 1 is the thing itself.

 

State-Space Search: Missionaries and Cannibals
``Once upon a time, three missionaries were being guided through a jungle by three cannibals to the nearest mission station. After some time, they arrived at the left bank of a wide river, filled with deadly snakes and fish. There was no way to cross the river without a boat. Fortunately, they found a row boat with two oars after a short search. Unfortunately, the boat was too small to carry all of them. It could barely carry two people at a time. Worse, because of the river's width there was no way to bring the boat back other than to row it back.

``Since the missionaries could not trust the cannibals they had to figure out a plan to get all six of them safely across the river. Luckily one of the missionaries had taken CISC-280 at UD and knew how to solve their problem. She devised a Scheme program to search a solution, implemented it on her laptop, ran it and used the computed solution to get them all safely to the other side of the river.''

What was the problem? The kind of cannibals in the story kill and eat missionaries as soon as there are more cannibals than missionaries at some place. Thus, our 280 graduate had to devise a plan that guaranteed that there were never any missionaries in the minority at either side of the river, or in the boat. However, the cannibals can be trusted to cooperate otherwise (they won't abandon any potential food, just as the missionaries won't abandon any potential converts).

Implement a Scheme program that finds a solution to the problem. Hint: solve this in steps, and make sure you have one step working before doing the next.

  1. Design an abstract data representation for each STATE of the river crossing. Define the appropriate CONSTRUCTOR and SELECTORS for the state. Some elements of your state abstract data type might be the number of cannibals on the right bank, the location of the boat, and so on.
  2. Determine the initial and final state of the game in your representation. Define a constant *start-state* using your constructor that represents the starting state.
  3. Design a function successors which consumes a state object and returns a list of all possible successor state objects, i.e., states reachable with one crossing. This list may include states in which the cannibals get to enjoy a meal, or even nonsensical states where there are -1 missionaries on the left-hand side of the river.
  4. Define a generalized version all-successors that consumes a list of states, and returns a list of states reachable with one additional crossing.
  5. Design a function legal? that accepts a state, and determines whether it is a legal (i.e. nobody gets eaten, not nonsensical) state.
  6. Design a generalized function legal-states that consumes a list of states and returns the sub-list of legal states.
  7. Design a function final? that consumes a state and determines if it is the final state.
  8. Design a generalized version final-states that consumes a list of states and returns the sub-list of final states.
  9. Finally, design a function that generates moves in the ``game'' until it has found a final state. Its result is the list of boat trips that the group has to make in order to get everyone from one side of the river to the other. The input would be a list of just the start state.

Hint: If the final program utilizes the first half-dozen functions, it will generate all states reachable with, say, seven crossings before it generates all those states reachable with eight crossings. Therefore you do not have to worry about cycles in solution attempts. QUESTION 10 :Why are there cycles and why is this a problem for a computer program?

Hint: You might wish to write the program in three stages. Your first program solution for part 9 might represent states in a manner that allows the program to find out whether a final state is reachable. This first program can return true if it is possible. Then, for the second edition, you must modify your state representation to include the list of crossings that got the group to this state. You can do this by simply altering your abstract data type with one more slot/element, and then update the other code as is appropriate. Of course, for the initial state the list-of-crossings-so-far is just the empty list.

For the third, final, and completely optional stage (that is, if you complete it, you will learn something but you won't get credit for it) eliminate all those states that represent solution attempts in which the same state would be reached (at least) twice. If you implement this third edition, you might wish to determine whether this measure saves time and how much time it saves.

You are welcome and encouraged to use Scheme's library functions as you see fit. This includes such operations as append, filter, map, etc. It will make your life easier (link).

Warning: The program can take about a minute to run on Strauss (or, if you mistakenly have an infinite loop, much, much, much longer......).  I print a little "." each time I search one move deeper; you should find a solution within 12 moves. If you want to know how to do this the right way, take CISC-481 (Intro to Artificial Intelligence)! :-)

Partial Credit: If you do not get the program to work, state so at the top of your solution. Turn in your complete work for each of the functions you finished instead. That is, show your abstract data type definition, program examples, documentation, function definition, and test cases. Alternatively, show the programs or data definitions from which you abstract. We will give  points for partial solutions, if they show you made a systematic effort for each sub-problem.