DCS 440 -- Homework 3: Search and Data Structures in Prolog

Due by Class Time, Wednesday October 18


Contents
Objective
Details
Hand In
File to start from
Clarification

Objective

For this assignment, you will set up a small number of prolog data structures and use them to define a handful of predicates. These predicates will complete a variant of the directions program from the week of September 25. The new directions program you complete will use lowest-cost-first search.

Details

First, design a prolog term that can store a path as a node in a search space. This term should be able to represent

  • the start of the path
  • the end of the path
  • the distance traveled in the path
  • the steps followed in the path, including each's name, distance and direction
    Update and clarification - as many of you have already found, it helps to represent the start and ending points of the steps followed in the paths here too. I think I was presuming that you would do this anyway; I was suggesting including the name, distance and direction in addition. Sorry about any confusion.

Remember, designing representations is a paper-and-pencil exercise and doesn't form an explicit separate part of your Prolog program. You should, however, define three predicates to characterize path structures
  • reaches(Node,Endpoint) will be true if the path represented by Node ends at the location Endpoint.
  • cost(Node,Amount) will be true if the distance traveled in the path represented by Node is Amount.
  • describe_path(Node) will print out the directions corresponding to path Node. Use same kind of format as illustrated by the directions program from class.

Second, define a predicate neighbor(Node,Neighbor) which is true if the node Neighbor in the search space can be reached in one step from the node Node in the search space. In other words, Neighbor should be a path that

  • starts out like Node
  • includes an additional path segment from the end of the path in Node to a new destination that the path has not yet traveled through
  • reflects the new endpoint and the new distance of the longer path

The initial file defines a predicate segment(Start,End,Direction,Distance,Name) that is true if there is way to go (called Name) directly from Start to End that runs roughly in Direction and has a length Distance. You should use this predicate in defining neighbor.

The initial file also defines a predicate neighbors(N,NN) as found in Computational Intelligence, in terms of the neighbor predicate you will define. Here is the definition:

neighbors(Node, Nodes) :- findall(Neighbor, neighbor(Node,Neighbor), Nodes).
It uses the built-in Prolog operation findall to tabulate all the elements Neighbor for which neighbor(Node,Neighbor) is defined.

Third, define predicates select(N,F1,F2) and add_to_frontier(Nodes,F1,F2) to implement a lowest-cost-first search. You should use the heap implementation that is part of the SICSTUS Prolog implementation. The initial file includes a statement to make that implementation visible to your program. For these predicates, there are two heap predicates that you will have to know about.

  • get_from_heap(Old, Key, Element, New) This predicate is true if Element with key Key is the element in the heap Old with the smallest key, and New is the heap that you obtain from Old by eliminating Element from it.
  • add_to_heap(Old, Key, Element, New) This predicate is true if New is the heap that you get by adding an element Element with key Key to the heap represented by Old.
The initial file contains a definition for a predicate find(F,G,P) which is true if node P is a path that reaches location G and which is accessible from frontier F. find follows the definition of search from Computational Intelligence.
find(F, G, P) :- select(P, F, _), reaches_goal(P, G).
find(F, G, P) :- select(N, F, F2), neighbors(N, NN), add_to_frontier(NN, F2, F3), find(F3, G, P).

Fourth, put everything together by defining a predicate go(S,E) that uses lowest-cost-first search to find and print out the shortest path from S to E. Use the predicate empty_heap(H) to create an empty frontier and use the predicate add_to_heap introduced previously to add the start state to the initial frontier for search.

Hand In

A copy of your code for the assignment, instructively but briefly commented, on paper or by email, at the specified time.