CS 15-212-ML: Assignment 2
Due Wednesday, September 23, 12:00 noon (electronically); papers at recitation.
Maximum Points: 100 (+10 extra credit)
Leonardo da Pisa, son of Bonacci, better known as Fibonacci ("Filius Bonaccii") is nowadays well-known mainly to mathematicians and computer scientists for the sequence of numbers that bear his name:
f0 = 1 |
f1 = 1 |
fn+2 = fn+1 + fn |
One of his major concerns in life (1180-1250) were, however, rabbits. In particular, he was interested in knowing how rabbits reproduce and, assuming to start with one male and one female rabbit, how many rabbits he would get after any fixed amount of time. For this purpose, he came up with the following (admittedly approximate) discrete model of rabbit reproduction:
Starting from one couple of young rabbits, the evolution of the rabbit population can be represented by the infinite sequence of Fibonacci trees of which the first five elements are as follows:
Each leaf in the tree represents a rabbit couple. A couple of young rabbits is represented as an empty circle, while a couple of adults is pictured as a square. Internal nodes contribute to the tree structure and can serve the purpose, for example, of computing the age of the rabbits.
The n-th element of this sequence, that we will denote as Tn, is a snapshot of the rabbit population at month n.
Given the following declaration describing the structure of Fibonacci trees
datatype fibTree = Young | Adult | Node of fibTree * fibTree
write an SML function nextFibTree, of type fibTree -> fibTree, that, given an object of type fibTree, creates a new fibTree of the next generation according to Fibonacci's specification of rabbit reproduction, as exemplified in the figure above.
Use nextFibTree to write a function createFibTree
of type int -> fibTree that, given a natural number
n, generates Tn. You may assume that n >= 0
, but
please document this in an invariant in your code.
An interesting property about Fibonacci trees is that for any natural number n, Tn+2 is a binary tree having Tn as its left subtree and Tn+1 as its right subtree. This is illustrated in the picture below.
On the basis of this property and of examples shown in class, devise an efficient implementation of the function createFibTree' performing the same task as the function createFibTree from the previous question. This function should minimize redundant computation. Carefully state and prove its correctness.
Write an SML function countFibTreeLeaves, of type fibTree -> int, that returns the total number of leaves of the given Fibonacci tree. Notice that on the tree Tn, this is the number of rabbit couples in the n-th month.
Prove the following mathematical property about Fibonacci trees:
Sets play an important role as the foundation of most areas in Mathematics. Mathematicians enjoy working with extremely large sets, far beyond infinity. Sets are also a useful form of abstraction in Computer Science, although they are seldom used in practice due to their high manipulation overhead. Ways to implement certain countable (i.e. mildly infinite) collections of data will be described further on in the course. In this exercise, we will instead concentrate on finite sets, related concepts (relations and graphs), and their use in a small application.
We consider a simple implementation of the set data structure based on the list type of SML. The following declaration serves this purpose:
type 'a set = 'a list
Lists can be exploited in different manners as a support to the representation of sets. The choice is left entirely to you: what matters is that the functions you are requested to implement manifest their expected behavior.
For this assignment we assume that the elements of the set belong to an equality type, that is, elements x and y can be compared with the expression x = y. You may wish to consult Paulson, Section 3.14: Equality Types, for more information.
Give a correct implementation of a structure Set :> SET that satisfies the following signature (accessible in the file ass2.sml in this assignment's directory)
signature SET = sig (* types *) type 'a set (* exceptions *) exception NotFound (* constants *) val empty : ''a set (* conversions *) val toList : ''a set -> ''a list val fromList : ''a list -> ''a set (* single set operators *) val insert : ''a * ''a set -> ''a set val remove : ''a * ''a set -> ''a set val isEmpty : ''a set -> bool val filter : (''a -> bool) -> ''a set -> ''a set val map : (''a -> ''b) -> ''a set -> ''b set val member : ''a * ''a set -> bool (* binary set operators *) val union : ''a set * ''a set -> ''a set val intersection : ''a set * ''a set -> ''a set val difference : ''a set * ''a set -> ''a set end;
and the specifications below for the values it mentions
p
evaluates to true.f
to the members of s.
A binary relation is a set having ordered pairs of objects as its elements. The set of objects that are allowed as the first components of these pairs form the domain of the relation. Similarly, the elements that can appear as the second component of the pairs form its codomain.
On the basis of this definition, the representation of relations is immediate:
type ('a, 'b) relation = ('a * 'b) Set.set
Use the operations contained in the structure Set you just wrote in order to define the structure Rel implementing some basic operations on relations, as specified by the following signature (file ass2.sml in this assignment's directory):
signature RELATION = sig (* types *) type ('a, 'b) relation = ('a * 'b) Set.set (* operators *) val image : ''a * (''a, ''b) relation -> ''b Set.set val preimage : ''b * (''a, ''b) relation -> ''a Set.set val diagonal : ''a Set.set -> (''a, ''a) relation end;
These operations ought to realize the following functionalities:
x
,
using the datatype:
datatype mexp = (* m *) X (* x *) | Real of real (* r *) | Sin of mexp (* sin( m ) *) | Cos of mexp (* cos( m ) *) | Exp of mexp (* e^m *) | Power of mexp * real (* m^r *) | Plus of mexp * mexp (* m1 + m2 *) | Times of mexp * mexp (* m1 * m2 *)In this format the function
1 + x^2 + sin( e^x )
could be
represented in many ways; two examples are:
Plus(Real(1.0), Plus(Power(X, 2.0), Sin(Exp(X)))) Plus(Plus(Real(1.0), Times(X, X)), Sin(Exp(X)))
MathExp :> MATHEXP
.
All of the functions should be evident from their names
(i.e., real 6.0 => Real(6.0)
)
The derivative
function should return a mathematical expression
that is the symbolic derivative of the argument. The transform
function takes a mathematical expression and returns its implementation as
an ML function. The evaluate
function should evaluate a
mathematical expression at a given real.
signature MATHEXP = sig (* types *) type mexp (* building blocks *) val x : mexp (* x *) val real : real -> mexp (* r *) val sin : mexp -> mexp (* sin( m ) *) val cos : mexp -> mexp (* cos( m ) *) val exp : mexp -> mexp (* e^m *) val power : (mexp * real) -> mexp (* m^r *) val plus : (mexp * mexp) -> mexp (* m1 + m2 *) val times : (mexp * mexp) -> mexp (* m1 * m2 *) (* operations *) val derivative : mexp -> mexp val transform : mexp -> (real -> real) val evaluate : (mexp * real) -> real end;
Recall the trigonometric differentiation rules
(d/dx)(sin x) = cos x and
(d/dx)(cos x) = - sin x.
Especially important is the chain rule: (f(g(x)))' = f'(g(x))g'(x).
derivative
function
correctly computes a mathematical expression representing the derivative.
Exp(Real(0.0)) Power(m, Real(0.0)) Plus(Real(0.0), m) Plus(m, Real(0.0)) Times(Real(1.0), m) Times(m, Real(1.0)) Times(Real(0.0), m) Times(m, Real(0.0))Add a function
simplify : mexp -> mexp
to both the signature and
structure that reduces these forms. For the purpose of these
simplifications, we will allow 0.00.0
to evaluate
to 1.0
. You can gain more points by implementing additional
simplifications.
/afs/andrew/scs/cs/15-212-ML/studentdir/<your andrew id>/ass2/ass2.sml