CS246 [Winter 2010] Assignment 4.

Version 0.3, 09 Feb 2010

Version 0.4, 15 Feb 2010

Version 0.5, 29 Feb 2010 (See note added below on the “p” command, at the end of this document)

Beware: Expect some changes to occur in this assignment.  Further changes are not expected.

Binary relations as an abstraction

You are to create software to manipulate binary relations such as

love:  { (Bob, Jane), (Jane, Fred) }

This relation, call it the “love” relation, can be read as: Bob loves Jane and Jane loves Fred.  This relation is a set of two pairs, the first pair is Bob and Jane and the second pair is Jane and Fred.  Pairs are ordered (so even if Bob loves Jane, Jane may not love Bob).  Relations are unordered sets, so the “love” relation can also be written equivalently as

{ (Jane, Fred), (Bob, Jane) }

Since a relation is a set, a relation, such as “love”, cannot contain more than one copy of the same pair.

You will implement a data abstraction, which is the concept of a binary relation, which can also be thought of as a table, e.g.,

love:

 SOURCE TARGET Bob Jane Jane Fred

To keep things simple, we sometimes write a relation such as “love” as simply:

love:

Bob  Jane

Jane  Fred

Here is another relation, the “like” relation

like:

Bob  George

Bob  Jane

In general, a binary relation contains zero or more pairs.  For this assignment, each item in the pair, such as Bob or George, is a string of characters.

The operations on binary relations include union (+), subtraction (-) and composition.  For example, for the “love” and “like” relations (see above), the union of “like” and “love”, written as like + love, is as follows:

like+love:

Bob  Jane

Jane Fred

Bob George

Relations can be subtracted, so the relation written as like-love contains all those pairs in like but not in love:

like-love:

Bob George

We can interpret this to mean that Bob likes George but he does not love him.

Another operation is called composition (or join), e.g., like*love.  If person p likes someone and that someone loves q then the pair p q is in the relation like*love as shown here.

like*love:

Bob Fred

We can interpret this to mean that Bob likes someone who loves Fred.  (That someone is Jane in this example.)

We will sometimes call a binary relation simply a relation.

Implementation of binrel class

Write a C++ class called binrel that supports operations such as +, - and * on binary relations. Each object of the class represents a binary relation.  Within each object that represents a relation is a C++ vector of pairs of strings, one pair of strings for each pair in the represented relation.  The size of the vector gives the cardinality (number of pairs) of the represented relation.  All relations are initially be empty.

The interface to the binrel class should be in the file binrel.h and its implementation should be in the file binrel.cpp.

This class should include the following public members:

void nullify ();                            // Make the binary relation have no pairs

bool isNull () const;                       // See if the binary relation has no pairs

void output();                              // Output in simple format

binrel& operator =(const binrel& rtSide);   // Assignment

binrel operator +(const binrel& rtSide);    // Union

binrel operator -(const binrel& rtSide);    // Subtraction

binrel operator *(const binrel& rtSide);    // Composition (binary join)

// There will be more functions here.

Implementation of the calculator

Your main program is used to manipulate relations.  It reads commands from the keyboard and produces output on the console.  One command is to create or “declare” a relation (initially empty) with a name such as love.   The main program  maintains a C++ vector of structs, whose two parts are the relation name and the relation’s value.  The value is an instance of the binrel class.

You program should make simple checks such as verifying that a relation is declared before it is used, reporting errors on the cerr stream.  All error messages should begin with the word ERROR.

The help command

The calculator outputs help information when you give it the ‘h’ command.  There is a function in help.cpp that prints out the list of commands.  You should study those files as they list commands that the calculator is to carry out.   Your main program should #include help.h.  Beware that the files help.h and help.cpp might change a bit.

Example calculator session

Below is an example interaction between a user and the relation calculator.

The parts in bold are typed by the user.

The parts in italics are data output by the program.

The other parts are prompts written by the program.

Welcome to binary relation calculator.  Type 'h' for help.

Command: d

Declare.  Give rel: love

Command: i

Insert pair.  Give rel src trg: love Bob Jane

Command: o

Output.  Give rel: love

Bob   Jane

Command: i

Insert pair.  Give rel src trg: love Jane Fred

Command: o

Output.  Give rel: love

Bob   Jane

Jane  Fred

Command: d

Declare.  Give rel: like

Command: i

Insert pair.  Give rel src trg: like Bob George

Command: i

Insert pair.  Give rel src trg: like Bob Jane

Command: o

Output.  Give rel: like

Bob   George

Bob   Jane

Command: +

Union.  Give relx rely relz: likeOrLove like love

ERROR: No such rel 'likeOrLove'

Command: d

Declare.  Give rel: likeOrLove

Command: +

Union.  Give relx rely relz: likeOrLove like love

Command: o

Output.  Give rel: likeOrLove

Bob   George

Bob   Jane

Jane  Fred

Command: q

Quitting.

Nondeterminacy.  Relations are unordered sets of pairs.  (The strings in a pair are ordered, but the pairs in a relation are not ordered.)  So the order in which pairs are output for a given relation is, at least in principle, immaterial.  You may want to keep the pairs in order of age, i.e., so that those that added to the relation longest ago are generally output earliest, but this is not required.

Related files.  You will be given a compiled (master) solution to this assignment.  You can run this under a student account to see if your solution gives the same answers.  Your output  (except when there are user errors) from your program should be the same, character for character, as the master solution.  You can get this master solution on your student account using the Unix commands:

curl http://plg.uwaterloo.ca/~holt/cs/246/2010/asgn04/relcalcdir/masterrelcalc > masterrelcalc

chmod 700 masterrelcalc

You will be given the makefile and the header files which can be accessed in a similar way.   You should write you program so the makefile works on it.

See this URL for files available to you (some in that directory have purposely been make non-viewable by you.)  See also files script.* which

you can use for testing.

The assignment.  This assignment has two parts as follows:

Part 4a.  Implement relcalc as described above.

Part 4b.  Make your program so that if it is given a –q (quiet) flag, as in relcalc -q, then the calculator writes no prompts. such as “Command:” to the user.  But if requested by the h command, the help file is still printed.

Inconsistency.  As pointed out by a student, the “script.rel” file uses an extra command, the “p” (for print) that

is implemented in the distributed solution, but is not documented.  This command takes a string (not containing white space) and prints it, somewhat like a simplified version of the shell “echo” command.  The file “script.rel” uses this “p” command.  You have a choice.  You can either ignore the “p” command, removing the lines that use it from “script.rel”.  Or you can implement the “p” command, including documenting it in “help.cpp”, for a bonus of 2 points.