CSCI 222 Rule-Based System Documentation

Rebecca Freeman Hall
Restaurant-Chooser Expert System

Introduction
The expert system I implemented is an aid to picky eaters looking to dine out in Chico. It's task is to classify where the user wishes to eat based on several facts that the user supplies. It does not have a large working memory of restaurants, but I picked them such that they span the criterion that the system knows about. Each restaurant is categorized with respect to type of food, (ie. mexican, italian, etc) relative price, (low, medium, high) class, (casual, semi-casual semi-formal) notable dish, (may have more than one, or none at all) and the times that they are open are also stored. I did not implement a snazzy user interface to collect the criterion from the user; intead, these values are set at the top of the file containing the code for the system. Once these values are set, the user need only use the query eatat(X) to generate a list of possible places to eat, and type a semicolon after each suggestion to get the next one.

Background
This project did not require any extensive research into other restaurant-picking expert systems. However, I used three books as references for learning Prolog: Artificial Intelligence Through Prolog by Neil C. Rowe, PROLOG programming for artificial intelligence (Second Edition) by Ivan Bratko, and Artificial Intelligence and the Design of Expert Systems by George F. Luger and William A. Stubblefield. I found the chapters on lists especially helpful. This system is sufficiently simple that the textbooks above contained enough information for me to write it without other references.

Description
As I mentioned in the Introduction, my expert system generates a list of restaurants that the user may want to eat at. It is implemented in Prolog on the linux operating system. It stores information about each restaurant (defined in Introduction), and determines which restaurants match the given criterion through backward chaining. The critical rules used to decide if a restaurant matches the criterion are the 'eatat' clauses. There are a large number of these; 4 for each restaurant. The idea behind this is the first 'eatat' clause for each restaurant defines the strictest match (ie. ALL possible criterion match). However, I wanted my system to allow 'don't cares' so the following three clauses check for fewer criterion. The last 'eatat' clause for each restaurant checks only if it is open at the specified time and if it is a favorite restaurant. Restaurants that are defined as favorite ALWAYS show up on the list of restaurants. (at the end of the list, if they don't match any other criterion and therefore show up earlier)

Sample Run #1
The following facts were set for this sample run:
% set preferences
foodtype(mexican).
mealtype(dinner).
dishtype(none).
pricetype(medium).
classtype(casual).
favorite('Frankies').
favorite('Paradise').
favorite('Chan Pheng').
favorite('El Ranchero').

The actual run:

4 ?- eatat(X).

X = 'La Comida' ;

X = 'La Comida' ;

X = 'El Ranchero' ;

X = 'El Ranchero' ;

X = 'Jacks' ;

X = 'Round Table' ;

X = 'Woodstocks' ;

X = 'Windys' ;

X = 'Carls Junior' ;

X = 'El Ranchero' ;

X = 'Frankies' ;

X = 'Chan Pheng' ;

No
This run actually demonstrates a successful run and/or an unsuccessful run, depending on how you look at it. It is successful in that the best matches come first, and it exhaustively finds ALL restaurants that match the specified criterion, but the way that I wrote the 'eatat' clauses allows duplicates and also matches some restaurants that don't meet all the criterion. The reason for the latter case is that since I allow 'don't cares' the less-specific clauses will match, hence Jacks, Round Table, Woodstocks, Windys, and Carls Junior show up on the list since they match the mealtype, classtype, and pricetype indicated. I decided to leave this in because it would require a lot more 'eatat' clauses to cover every possible combination of criterion and I don't think it detracts from the accuracy too much since these always show up later in the list than best matches. As for the duplicates, I believe they show up when less-specific 'eatat' clauses match in addition to more-specific clauses, although I thought that once a match was found for a particular restaurant it wouldn't try to match it again. Apparently that is not the case, and I gave up on trying to fix this after experimenting with the use of cuts (the ! character in prolog) to stop matching after a match was found, but all I could get it to do was stop after matching ANY 'eatat' clause, therefore giving only one answer. This was unacceptable so I also tried rearranging the order of the 'eatat' clauses to see if that would have any effect, but this attempt was also unsuccessful. So this is a genuine bug, but I decided not to spend any more time on it since at least the repetition accurately tells the user that the restaurant matches REALLY well and therefore emphasizes the degree of certainty in that choice.

Sample Run #2
The following facts were set for this sample run:
% set preferences
foodtype(none).
dishtype(none).
mealtype(lunch).
pricetype(low).
classtype(casual).
favorite(none).

The actual run:

4 ?- eatat(X).

X = 'Tacos Cortez' ;

X = 'Cozy Diner' ;

X = 'Taco Bell' ;

No
This run represents a completely successful execution of my program. It differs from the first run in that only the least-specific clause matches for each restaurant, resulting in a single result for each restaurant.

Limitations
This system is very simple and therefore limited in many ways. As mentioned in the Introduction there is no user interface to interactively get parameters from the user. I considered putting an interface in, but since the user would need to input more complex syntax than yes or no, I discovered it would involve quite a bit of extra code to implement this. Also there are the bugs mentioned above. In addition, in order for this system to be really useful it would need to have information about a lot more restaurants.

Goodness
I am very happy with the degree of usefulness even this simple program offers. Although it has a small list of restaurants, I can put in what I generally feel like eating and get a valid list of places I might want to eat. I also like the "favorite" feature because it really simulates how we decide to eat -- we always have a default list of places we always feel like eating.

Where to go from here...
This program would definitely benefit from a bit more time spent fixing the above limitations. Also I have the nagging feeling that the code itself could be simplified. I think I might have went the "long way" on how to represent the clauses and facts. I think my inexperience with this type of programming is at fault here, and hope that with more practice this simplification will come naturally, as it does in other types of programming. For the time being, I left the code in its original state because it works (mostly!), and represents the instinctual way I went about solving the problem. This might come in handy later on when I get more familiar with AI shells and can look back at my 'first try' to see how I was approaching the problem.

In writing this program, I quickly grew tired of repeating every combination of rules to satisfy the "don't care" functionality, which is why not every possible combination is accounted for. I don't know if there is another way to do this in Prolog, or if a non-rule-based system with better organization of the problem might offer a more flexible solution, but this is definitely an area that I intend to explore for the next assignment.