The problems in this assignment finish up the Unit Calculator application in rex with a mutually recursive pair of functions. Also, some other data structures in rex are considered, as well as a prelude of what's to come: Java.
You are asked to construct several function definitions in rex and test them. You should submit your rex functions in a single file named hw3.rex. When you submit with
cs60submit hw3.rexbe sure to indicate that your assignment number is 3.
You will also need to create a file named OpenList.java . To submit this part of the assignment, use
cs60submit OpenList.javaand again indicate that your submission number is 3.
This assignment uses material through Chapter 5 in the text, though the material needed to handle this assignment will be presented in class also.
Test cases for each of these problems appear in the directory
/cs/cs60/as/a3 . The names of the test-case files for rex
are Test#.in, where # is 1 - 5.
To test a particular rex function in hw3.rex, use
% rex hw3.rex < /cs/cs60/as/a3/Test1.inwhere Test1.in can be replaced wih any of the rex test files.
To test your java class, OpenList, you can copy the test code in /cs/cs60/as/a3/OpenList.examples (in the main function) to your OpenList class's main function and then run it. The correct output is in /cs/cs60/as/a3/OpenList.out and you can be sure that your output is the same with the unix diff command (from the directory with your compiled java code):
% java OpenList | diff - /cs/cs60/as/a3/OpenList.outIf you see nothing (that is, no "differences" occur), you know your code is producing the correct output. If you do see lines beginning with "<", they are output lines that your program printed , but do not appear in the OpenList.out file. Lines beginning with ">" appear in that file, but not your program's output.
When the lists in a quantity list (see assignment 2 for the definition of a quantity list) contain only basic units, we'll say that the quantity list is normalized. Recall that basic units are those which do not appear on the left-hand side of any entry in the unit database. That is, they are irreducible.
In order to convert one quantity to another, we must both normalize and simplify the quantities. Using your function conv_unit, create a function called norm_unit(s,DB) that returns a normalized representation of the unit s. The inputs to norm_unit(s,DB) are a string s representing a unit and a unicalc database DB.
Here's how norm_unit(s,DB) will work: in the case that conv_unit finds the unit as some left-hand side of an entry in the database, you want to go through the numerator and denominator lists of the right-hand side of that entry (quantity list). As you go through the numerator and denominator, normalize each unit that appears and multiply them together. Since your multiply function always yields a simplified result, you are guaranteed that the product of a list of units is simplified and sorted. Once you have normalized both the numerator and denominator, use your function divide to get the overall result of normalization and then combine with the multiplier. If conv_unit doesn't find s in the database, norm_unit should return the same thing conv_unit does -- namely, [1.0, [s], []].
Here are some example runs of norm_unit. There are two unicalc database files in /cs/cs60/as/a3/ : one is called unicalc_mini_db.rex and a much larger one is called unicalc_db.rex. Both files define the variable db, so only include one of the two files as you test... .
rex > sys(in,"/cs/cs60/as/a3/unicalc_mini_db.rex");
rex > norm_unit("second",db);
[1, [second], []]
rex > norm_unit("hour", db);
[3600, [second], []]
rex > norm_unit("ohm", db);
[1, [kg, meter, meter], [ampere, ampere, second, second, second]]
Recall that a quantity list always has the form [Amount, N, D], and N and D consist of lists of units (strings). So, to normalize a quantity list, you would apply norm_unit to the elements in N and D, and then multiply and divide as necessary. It turns out that norm and norm_unit can be expressed mutually recursively, with each calling the other (and perhaps itself, too). Rex (as well as Java) can handle mutual recursion, so you may want to take advantage of that. (To write norm and norm_unit without mutual recursion is possible, but more difficult.)
Some examples of norm in action:
rex > norm([20.0, ["hour"], []], db); [72000, ["second"], [] ] rex > norm([15.0, ["ohm"], ["volt"]], db); [15, [], [ampere]]
rex > divide(norm(A, db), norm(B, db))
If direct conversion is possible, the numerator and denominator of this result should both be empty lists. If there is a mismatch, the numerator or denominator or both will not be empty. Write a user interface function convert such that convert(A, B, DB) will perform the conversion and output the units if a direct conversion is possible, or will output "There is a mismatch in units." when a direct conversion is not possible.
Follow the form of these two examples:
rex > convert([1, ["mile"], []],
[1, ["inch"], []], db);
multiply by 63360 or divide by 1.57828e-05
rex > convert([1, ["mile"], ["second"]],
[1, [], []], db);
There is a mismatch in units.
For converting
numbers to strings, you may wish to use the rex built-in function
make_string
that makes a string of its argument, and concat that concatenates an
arbitrary number of string arguments.
Create the function biggestFan(G) that takes a graph G (as a binary relation) as input and outputs the node of G that has the biggest fan-in. The fan-in of a node is simply the number of parents of that node, so biggestFan returns the node with the most parents.
If there is a tie for the biggest fan-in, you may return any one of the correct nodes. For example:
rex > biggestFan([ ["A","D"], ["B","D"], ["C","D"], ["A","E"],
["D","E"], ["E","F"], ["F","A"] ]);
D
rex > biggestFan([ ["A","B"], ["B","C"] ]);
B
where the last answer could also have been C. NOTE Your predicate will only be given ACYCLIC graphs as input. Thus, you don't have to worry about "running around in circles" searching for whether there is a path from a to b, because there will be no cycles in the graph. Also, remember the graphs are directed. For example,
rex > reachable("A", "F", [ ["A","D"], ["B","D"], ["C","D"], ["A","E"],
["D","E"], ["E","F"] ]);
1
rex > reachable("C", "A", [ ["A","B"], ["B","C"] ]);
0
Write a java class named OpenList that implements an open list data structure. Write your class in a file called OpenList.java. Open lists are the type of linked list that rex uses. Open lists should never be modified (so that there is no worry about side effects) -- instead, each function returns a newly created list (or whatever data is appropriate).
There is an example implementation of a Stack data structure in the file /cs/cs60/as/a3/Stack.java. Feel free to use it as a model for your OpenList class. In order to test the Stack class, copy the Stack.java file mentioned above to the directory in which you're working on this assignment. The command
javac Stack.java
will create a file named Java.class in your directory.
Then running
java Stack
will execute the code in the main function of Stack.java
that tests some of the Stack data structure's abilities.
Running your OpenList code works in the same way.
For your OpenList class, implement the following functions
(often called methods in Java):
public static void main(String[] arg)
that creates some OpenLists, performs some operations
on them and the prints out the results. If you can run all of the test
code in the main method in the file OpenList.examples
mentioned above, you should feel confident that your methods
are correct. See the "Testing your code" section for
more detailed instructions on how to test your Java code.
broadReach([ ["A", "B"], ["B","B"], ["B","C"], ["B","D"] ]);
[ ["A","B"], ["A","C"], ["A","D"], ["B","B"], ["B","C"], ["B","D"] ]
broadReach([ ["A", "B"], ["B","C"], ["C","A"] ]);
[ ["A","A"], ["A","B"], ["A","C"], ["B","A"], ["B","B"],
["B","C"], ["C","A"], ["C","B"], ["C","C"] ]