## Solutions – Practical 4

February 2, 2010

The code you had to write for this practical gives examples of the basic paradigms for recursion over trees. Unfortunately, the instructions given don’t quite lead to a complete implementation of the optimisations I had in mind.

In this note, I give two “solutions”: one, Optimise, based on the instructions; and another, GoodOptimise, that ignores the erroneous instruction.

### reshape

This code gives a template for top-down application of transformations to a tree. The first two lines apply the transformations repeatedly, as long as they apply; the next two lines apply the transformations recursively to subtrees, and recombine the results appropriately; the final line gives a terminal case, it applies only when the recursion reaches a leaf node of the tree.

### amalgam

This function again follows the top-down paradigm.

In Optimise, the first six lines apply the transformations repeatedly. (In the first two lines there is no point in reapplying the transformations, as we can see that they would not apply.) The final three lines again implement a top-down recursion over the tree.

The error in the instructions appears here. Consider the expression (5 × 4) + 3 The function amalgam will not reduce this, whereas we would expect it to reduce to the literal, 60. One analysis of the problem is that the transformations

should be applied bottom-up. In GoodOptimise, these transformations are incorporated in the function elim, (by adding them to the subsiduary function delim, since this already uses a bottom-up recursion.

### elim

To implement a bottom-up recursion, we separate a single application of a transformation into a subsiduary function, delim, the main function, elim, applies these transformations bottom-up, by first transforming any subtrees, and then attempting to apply a transformation to the result.

### rightHeight

This is a straight-forward recursion over the tree; it follows the pattern of the datatype declaration — except that we don’t need to distinguish the two kinds of leaf.

### reorder

We apply the re-ordering transformation bottom-up. The subsiduary function order implements the transformation, and the declaration of reorder implements the bottom-up recursion.

### optimise

Combining these functions together gives a function that may significantly reduce the size, and stack requirements, of the the stack code produced for an algebraic expression. Other optimisations, such as grouping terms involving the same identifiers, could be included in the same way.

### Conclusion

As well as giving examples of top-down and bottom-up recursion over trees, this example demonstrates the subtlety needed to design correct algorithms. The code given by following the original instructions would correctly reduce expressions containing either only additions, or only mutiplications; but it does not cater for the interactions between them.

structure Optimise: OptimiseSig = struct
open Expn

fun reshape (x ++ (y ++ z)) = reshape ((x ++ y) ++ z)
| reshape (x ** (y ** z)) = reshape ((x ** y) ** z)
| reshape (x ++ y)        = reshape x ++ reshape y
| reshape (x ** y)        = reshape x ** reshape y
| reshape  x              = x

fun amalgam (Lit m ++ Lit n)        = Lit (m + n)
| amalgam (Lit m ** Lit n)        = Lit (m * n)
| amalgam ((x ** Lit m) ** Lit n) = amalgam(x ** Lit(m * n))
| amalgam ((x ++ Lit m) ++ Lit n) = amalgam(x ++ Lit(m + n))
| amalgam ((x ** y) ** Lit n)     = amalgam((x ** Lit n) ** y)
| amalgam ((x ++ y) ++ Lit n)     = amalgam((x ++ Lit n) ++ y)
| amalgam (x ++ y)                = amalgam x ++ amalgam y
| amalgam (x ** y)                = amalgam x ** amalgam y
| amalgam  x                      = x

fun delim (Lit 0 ** x) = Lit 0
| delim (x ** Lit 0) = Lit 0
| delim (Lit 1 ** x) = x
| delim (x ** Lit 1) = x
| delim (Lit 0 ++ x) = x
| delim (x ++ Lit 0) = x
| delim  y           = y

fun elim (x ++ y)      = delim(elim x ++ elim y)
| elim (x ** y)      = delim(elim x ** elim y)
| elim x             = x

fun rightHeight (x ++ y) = Prelude.max (rightHeight x) (1 + rightHeight y)
| rightHeight (x ** y) = Prelude.max (rightHeight x) (1 + rightHeight y)
| rightHeight x = 0

fun order (x ** y) = if rightHeight y > rightHeight x then y ** x else x ** y
| order (x ++ y) = if rightHeight y > rightHeight x then y ++ x else x ++ y
| order x        = x

fun reorder (x ++ y) = order(reorder x ++ reorder y)
| reorder (x ** y) = order(reorder x ** reorder y)
| reorder x        = x

val optimise = reorder o elim o amalgam o reshape;
end;

structure GoodOptimise: OptimiseSig = struct
open Expn

fun reshape (x ++ (y ++ z)) = reshape ((x ++ y) ++ z)
| reshape (x ** (y ** z)) = reshape ((x ** y) ** z)
| reshape (x ++ y)        = reshape x ++ reshape y
| reshape (x ** y)        = reshape x ** reshape y
| reshape  x              = x

fun amalgam ((x ** Lit m) ** Lit n) = amalgam(x ** Lit(m * n))
| amalgam ((x ++ Lit m) ++ Lit n) = amalgam(x ++ Lit(m + n))
| amalgam ((x ** y) ** Lit n)     = amalgam((x ** Lit n) ** y)
| amalgam ((x ++ y) ++ Lit n)     = amalgam((x ++ Lit n) ++ y)
| amalgam (x ++ y)                = amalgam x ++ amalgam y
| amalgam (x ** y)                = amalgam x ** amalgam y
| amalgam  x                      = x

fun delim (Lit m ++ Lit n) = Lit (m + n)
| delim (Lit m ** Lit n) = Lit (m * n)
| delim (Lit 0 ** x)     = Lit 0
| delim (x ** Lit 0)     = Lit 0
| delim (Lit 1 ** x)     = x
| delim (x ** Lit 1)     = x
| delim (Lit 0 ++ x)     = x
| delim (x ++ Lit 0)     = x
| delim  y               = y

fun elim (x ++ y) = delim(elim x ++ elim y)
| elim (x ** y) = delim(elim x ** elim y)
| elim x        = x

fun rightHeight (x ++ y) = Prelude.max (rightHeight x) (1 + rightHeight y)
| rightHeight (x ** y) = Prelude.max (rightHeight x) (1 + rightHeight y)
| rightHeight x        = 0

fun order (x ** y) = if rightHeight y > rightHeight x then y ** x else x ** y
| order (x ++ y) = if rightHeight y > rightHeight x then y ++ x else x ++ y
| order x        = x

fun reorder (x ++ y) = order(reorder x ++ reorder y)
| reorder (x ** y) = order(reorder x ** reorder y)
| reorder x        = x

val optimise = reorder o elim o amalgam o reshape;
end;

(C) Michael Fourman 1994-2006