|
|
Minutes of Meetings of the Algebra of Programming Research Group in 2001
-
Michaelmas Term 2001 (all Fridays)
-
-
Summer Break 2001 (all Fridays)
-
-
Trinity Term 2001 (all Tuesdays)
-
-
Trinity Term 2001 (all Fridays)
-
-
Hilary Term 2001 (all Fridays)
-
-
Friday, 30th November 2001
-
Richard spoke about how we can define axioms for arithmetic coding and translated them into a relational programming style. The axioms for an arithmetic coder are:
1) encode [] = [0, 1)
2) encode (xs ++ ys) is a subset of encode xs
3) encode (xs ++ [p]) intersect encode (xs ++ [q]) /= empty => p = q
He also mentioned a new method for inverting programs, based on the way we invert arithmetic coding. If there is some h such that
x = foldl f y (z:zs) => x /= y and h x y = z, then
unfoldr (g (foldl f y zs)) y = zs where
g x y = if x == y then Nothing else Just (h x y, f y (h x y)).
Jeremy told us about minimum edit distances and minimum cost spanning trees.
-
Friday, 23rd November 2001
-
Last meeting was used to discuss people's thoughts on the Countdown
Problem again. Ross has managed to significantly improve the performance
of his algorithm by using a series of rewrite rules:
(a + b) + c => a + (b + c)
(a - b) + c => (a + c) - b
(a - b) - c => a - (b + c)
a + (b - c) => (a + b) - c
He also managed to achieve a performance increase by memoising the results.
Shin has been thinking about the problem in terms of closures of relations and here are his comments on what he said.
To establish the background, I was trying to derive an algorithm
(for the count-down problem) and in one of the phases I need to
build all legal expression trees bottom-up.
I therefore need an algorithm to compute the closure of a relation
of type A*A -> A. There is an algorithm which is basically a direct
extension of the one in 'the book' and looks intuitively
correct, but I was not able to prove it in the meeting today. I
believe I've constructed a proof just now.
In chapter 6 of AoP there is a derivation of a recursive
equation for computing R* (the closure of a relation R :: A -> A).
We start with the specification (I'll denote union by U and fixed-point
operator by fix. For ease of reading, I'll write relations in small
letters):
close(p,q) = p U fix(x: q U r.x - p)
When p = 0, the above definition reduces to
close(0,q) =fix(x: q U r.x) = r* . q
So we can use close to compute r* given q as the initial value.
It was then derived that:
close(p,0) = p
close(p,q) = close(pUq, r.q - (pUq))
To generalise close to a relation taking two arguments, a natural
specification to start with is:
close(p,q) = p U fix(x: q U (r.(x*x) - p))
But it does not work. After some trial and error, I came up
with the following specification:
close(p,q) = p U fix(x: q U (r.((x*x) U (x*p) U (p*x)) - p))
The derived algorithm is:
close(p,0) = p
close(p,q) = close(pUq, r.((p*q) U (q*p) U (q*q)) - (pUq))
The derivation goes:
close(p,q)
= { definition }
p U fix(x: q U (r.((x*x) U (x*p) U (p*x)) - p))
= { x U y = x U (y-x) }
p U fix(x: q U (r.((x*x) U (x*p) U (p*x)) - (p U q)))
= { rolling }
p U q U fix(x: q U
(r.(((qUx)*(qUx)) U ((qUx)*p) U (p*(qUx)))
- (p U q)))
= { claim that the two long chains of unions are
equal; see below }
p U q U fix(x: q U
(r. ((p*q) U (q*p) U (q*q) U
(x*x) U (x*(pUq)) U ((pUq)*x)) - (pUq)))
= { (r.) and (-(pUq)) distributes into union }
p U q U fux(x: q U (r . ((p*q) U (q*p) U (q*q)) - (pUq))
U (r . (x*x) U (x*(pUq)) U ((pUq)*x) - (pUq))
= { folding the definition of close }
close(p U q, r . ((p*q) U (q*p) U (q*q)) - (pUq))
The claim to prove in the big step above is that the two horrible
looking chain of unions indeed equal. We use the following fact:
(a U b) * (c U d) = (a*c) U (a*d) U (b*c) U (b*d)
The claim can be proved as:
((qUx)*(qUx)) U ((qUx)*p) U (p*(qUx))
= { expanding all the terms }
(q*q) U (q*x) U (x*q) U (x*x) U
(q*p) U (x*p) U (p*q) U (p*x)
= { simply rearranging }
(p*q) U (q*p) U (q*q) U
(x*x) U (q*x) U (p*x) U (x*q) U (x*p)
= { folding the last four terms }
(p*q) U (q*p) U (q*q) U
(x*x) U ((pUq) * x) U (x * (pUq))
-
Friday, 16th November 2001
-
Richard gave us the latest version of his derivation of arithmetic coding, which goes like this:
encode :: [Char] -> [Bit]
encode = incode (0, 1)
incode (l, r) cs
| 2 * r <= 1 -> 0:incode (2 * l, 2 * r) cs
| 1 <= 2 * l -> 1:incode (2 * l - 1, 2 * r - 1) cs
| null cs -> [1]
| otherwise -> incode ((l, r) (+) (a, b)) (tail cs)
where (a, b) = subint (head cs)
(l, r) (+) (a, b) = (l + (r - l) * a, l + (r - l) * b)
There is still a problem in that changing to the integer version of the algorithm is not a data refinement.
Shin spoke about the Countdown Problem (named aftyer the TV programme) in which you have to apply + - * and / to six numbers, using each number only once, to obtain a randomly chosen target number.
-
Friday, 9th November 2001
-
Ross began proceedings with a talk on finite state automata in Haskell,
after which we had Shin's revised proof of his converse function theorem.
The new proof uses well-foundedness instead of F-inductivity and
F-reductivity.
Shin has also been doing some reading on functional quantum computing, and
how quantum computers can reduce the time required for some kinds of
algorithms.
Richard has been thinking about the conditions under which
unfoldr f . g = unfoldr f' for certain f, g and f'. This is useful for the
derivation of arithmetic coding from its specification.
-
Friday, 2nd November 2001
-
The subject of the discussion at the last meeting was arithmetic coding.
Richard is interested in deriving a program which implements the algorithm
from first principles. He began by defining the encoding function as
follows:
encode :: [Char] -> [Bit]
encode = toBits . contract . map bounds
where toBits is the function taking a range (represented as a pair of
Reals (left, right)) to the shortest sequence of bits representing a
number in the range, bounds takes each characted to an interval
representing its probability of occurrence, and
contract = foldl narrow (0, 1)
where narrow (l, r) (a, b) = (l + (r - l) * a, l + (r - l) * b)
Geraint suggested that it might be more helpful to represent ranges as the
pair (left, length) instead of (left, right), while Jeremy proposed that
it would be clearer to use the notation a[l, r] instead of l + (r - l) * a.
It turns out that narrow is associative, so contract = foldr narrow (0, 1).
Barney then attempted to explain how the integer-valued version of the
coding algorithm works, and the (small) tradeoff that occurs because the
compression becomes slightly less with this method.
-
Friday, 26th October 2001
-
To begin with, Richard spoke about the problem of computing
minlength {bs | l <= frac bs < r} where frac = foldr op 0, and
op b r = (b + r) / 2.
Jeremy has been working on a method of assigning distinction / pass / fail
marks to MSc students. The problem is to work out where the borderlines
fall under different mappings, p, from grades achieved in the exams to
degree results. We can define a preorder on the lists of exam results by
taking the pointwise order after sorting the lists of results. Under this
ordering, p must be monotonic - ie better grades in the exams lead to
better degree results. Several methods for determining where the
borderlines lay under vaious mappings p were discussed, including
zigzagging across the borderline and dividing the set of all possible
sets of grades up into bite-sized chunks and considering each chunk
separately.
Finally, Shin gave a proof of his converse function theorem. He is going
to try to simplify the proof by avoiding using the notions of
F-inductivity and F-reductivity.
-
Friday, 19th October 2001
-
Jeremy explained the class of bracketting problems, focussing
in particular on constructing trees of minimum height. He showed
that this problem could be solved by a greedy algorithm but he wanted
to solve it by a thinning algorithm instead. This meant, by
definition, keeping more than one solution at each stage.
Eventually Shin suggested a suitable ordering on which to
thin, whereby trees are only compared pointwise if their spines have
equal length. As a separate topic, Shin introduced the group
to Erwig's recent JFP paper on graph algorithms. Graphs are
represented using an inductive datatype and can be built up
by repeatedly adding nodes. Each node contains lists of incoming
nodes and outgoing nodes.
-
Friday, 13th July 2001
-
Richard wished to derive the program he had written to compute the
pattern-matching statistics of a string. He specified it as the
result of mapping a certain function on the text over the initial
segments of the pattern. Then he wrote the function on the text
as a fold-left, applied the scan lemma and considered thinning the
result. He finished by discussing the intended data structure of
suffix dags and the unrelated topic of space-efficient
representations of binary search trees.
-
Friday, 6th July 2001
-
Pedro had written a polytypic predicate that tested whether a value
was in the domain of a function. He had hoped to define the predicate
perfect as the domain of the unembedding function on nests written
as an unfold. Unfortunately, for lazy functional languages, he had
defined instead a predicate that tested whether the shape of the input
was completely defined. He then tried to define perfect by composing
this predicate with the unembedding function but the resulting
predicate could never return false.
-
Friday, 29th June 2001
-
As a prelude to his main question, Shin continued last
week's discussion on inductive relations, focussing on a
theorem which related the entireness of a hylomorphism to
the entireness of its parameters.
Shin then proved the converse function theorem, which expresses
the converse of a function f as a fold with a
relation R. He asked how the proof could be saved if
f need not be entire. He derived a further condition which said
that R and the fold with R must have the same range but
Roland said this was unlikely to be satisfied.
Roland explained how to make any amount over 13 cents
from 3 cent and 8 cent pieces alone. He wanted a
constructive (no need to know the method
beforehand) proof by induction that one could
always do this for values over a certain amount,
generalising the problem to relatively prime
X and Y cent pieces.
Roland conjectured in terms of X and Y, an expression for
the number Z such that every number greater than or equal to Z
is the sum of positive multiples of X and Y.
-
Friday, 22nd June 2001
-
Ian, Richard, and Shin rearranged the definition of the efficient fold
for nests in the hope that Ian might be able to prove the uniqueness
theorem.
Barney explained range encoding, which compresses strings far more than
Huffman encoding does. Each string corresponds to a range, which narrows
as the string lengthens. The encoding of the string is the lowest least
precise number in that range. Much of his talk concerned the
implementation details of how to avoid underflow.
Richard has written an efficient O(mn) program to compute the matching
statistics for a pattern of length m inside of text of length n. He
compared suffix trees with suffix dags.
-
Tuesday, 12th June 2001
-
Jeremy wrote up the generalised fold and the efficient fold
for nests. Richard disputed Hinze's claim that the latter was
more efficient but Jeremy convinced the group that it was,
since it had no nest-to-nest transformations. Clare said she
might be able to show that efficient folds had unique solutions
by generalising a proof at the end of Bird and Paterson's paper.
To do this, she needed to understand inductive relations. The group
will now meet on Fridays instead of Tuesdays, starting on June 22.
-
Tuesday, 5th June 2001
-
Ian wanted to know if efficient folds satisfied a universal property.
He explained the advantages of efficient folds, why they were needed
in proofs (to write maps), their typings, and their definition for
nests in Haskell, contrasting them with simple folds and generalised
folds. Universal properties have two halves: a definition (here
trivial) and a uniqueness theorem. Jeremy observed that for standard
folds, the universal property was equivalent to the fusion law.
-
Tuesday, 29th May 2001
-
Barney gave a three-axiom definition of a suffix tree, a data
structure that can be used to look up a substring in a long
text file. Each edge is labelled with a string, but for
convenience, Barney labels each node too with the path to it,
so each node has a substring but not vice versa. He explained
Wiener's algorithm to build a suffix tree for a string in linear
time and space. Richard opined that the algorithm could be better
described in a functional style as a fold on the tails of a
list to build a tree. Reasoning about the algorithm's efficiency
involved too many details of Wiener's exact implementation
for the group to be satisifed that it used as little time and space
as the author claimed.
-
Tuesday, 22nd May 2001
-
Richard described the latest variant of the Burrows-Wheeler transform
to have caught his interest. Manzini sorts the rotations using only
the first k characters of each. Remarkably, the transform is still
invertible (and Richard can prove this) even though the matrix (the
sorted list of rotations) cannot be recovered in full. The output
is the last column of the matrix and only the first k columns can
be reconstructed, but the original input can be worked out from
this information alone.
-
Tuesday, 15th May 2001
-
Pedro uses zips to write embeding functions on nested datatypes,
because his target datatypes are different from those suggested by
Okasaki. His functor category is built from CPO, which is easier to
handle as a base category than Rel is. He constrains the
form of his nested datatypes to keep both the embedding
and the unembedding operations functional (and therefore
implementable). He can derive as a simple fold a predicate
that tests whether a value is in the domain of the unembedding function.
-
Tuesday, 8th May 2001
-
Richard talked about another variation of the Burrows-Wheeler
transform in which an alternating lexicographic ordering is used
in place of lexicographic ordering. He claimed that the transformation
is still invertible. He then mentioned another variation proposed
by Barney to deal with compressing Haskell scripts, which involves
riffling.
Shin summarised the recent work of the Tokyo University group
on longest segment problems.
The group then discussed possible future work of each member.
Jeremy will look into Mendler's datatype.
-
Tuesday, 1st May 2001
-
Barney talked about a variant of the Burrows-Wheeler
transform: compute the sorted list of rotations, and output not
the last column, but the penultimate column instead.
He had discovered a pair of inputs which demonstrate that
the transform is not injective, and therefore not invertible
either. Extra information could restore its injectivity but
so much was needed as to make it useless for data compression.
However, Barney discovered that simply permuting the rotations
was another way to make the transform invertible again.
Ian asked how to write generalised folds for alternating lists.
Finally, Richard talked about Dijkstra's problem of designing
a non-deterministic algorithm to tile a chessboard with dominoes.
A coreflexive relation could be used to enforce an
invariant on the state of the board.
He debated with Geraint whether backtracking could be avoided.
-
Friday, 27th April 2001
-
Jeremy had written a paper about necessary conditions
on a relation that can be expressed as a fold.
Bart Jacobs had then told him of an alternative simpler
(not using kernels) congruence
(or "lifting relations") condition, which he explained by
structural induction on the polynomial base functor. However,
Richard used the universal property to show that Jacobs'
condition was just that the relation was simple.
Jeremy also gave a dual condition (using invariants)
for unfolds, equivalent to entireness, and considered
extending the conditions to partial functions.
-
Friday, 20th April 2001
-
Richard suggested a variation to the Burrows-Wheeler transform
where, instead of the last column, the penultimate column of
the sorted rotations was taken. To reconstruct the rotations
from the penultimate column, it was necessary to compute the
square roots of a permutation. However, there are more than
one square roots of a permutation and it was unclear
which one to use. The group tried some examples but did not
come to a conclusion how it could be done.
-
Friday, 30th March 2001
-
Ian described how to show that nested relators commute with
converse. Shin announced a further problem that he and Richard had
encountered with their work on the Burrows-Wheeler transform.
Clare was stuck with the "Id" case of her proof that
her efficient folds were equal to her generalised folds
composed with maps.
Finally, Jeremy explained a meaning-preserving transformation
on programs that Ralf Lammel had recently mentioned called
refactoring. It can be used to rename variables and tidy up class
hierarchies. More interesting applications in the functional
programming setting may include the automated introduction of monads.
-
Friday, 23rd March 2001
-
Richard had greatly simplified Shin's derivation of the converse of
the Burrows-Wheeler transform. However, Jeremy pointed out that the
point-free style of his proof was not rigorous enough since some
functions depended on the input string, which therefore couldn't
be omitted. A notation for modulo equality might allow Richard
to preserve his proof.
-
Friday, 16th March 2001
-
Ian explained to Richard the difference between his definition of
generalised folds and Clare's. Then Richard talked about the
contravariant property of a function apply that he had just invented;
it permutes a string according to a given function on indices.
The meeting lasted less than an hour.
-
Friday, 9th March 2001
-
Richard started the short meeting by explaining how a simple coding
trick could be used to reduce the number of comparisons needed to
sort the tails of a list. Barney belived the problem could be solved
in linear time and tried to construct an algorithm to do this.
Ian's notational difficulties with generalised folds were also
briefly discussed once more.
-
Friday, 2nd March 2001
-
Richard tried to show that his function sperm could be computed
functionally in O (n log n) time, where n is the length of the input
list. It required a logarithmic number of passes, but some of them
appeared to take longer than linear time.
Shin showed that the informal algorithm given by Richard four weeks
ago was indeed, as then claimed, the converse of the Burrows-Wheeler
transform. Ian and Jeremy briefly explained the higher-order
naturality property of zips, which Shin had needed to use.
Finally, Richard discussed the problems Ian was having with writing
generalised folds generically. Clare suggested he should use a
bottom-up approach.
-
Friday, 9th February 2001
-
Richard proposed that the number of comparisons needed to sort
the list of tails of a list is O (n log n) but he had no proof of this.
Shin has verified the candidate inverse of the Burrow-Wheeler transform.
Oege had conjectured that interpretting a lambda-term in Set and
then turning it into a relation gave the same result as interpretting
the lambda-term in Rel directly. Jeremy presented Nick Benton's
proof of this, which took up most of the meeting.
Then he returned to the last week's relational extension of his
characterisation of folds. He produced counterexamples (one due
to Clare) given two different definitions of kernel. Finally, Richard
and Jeremy discussed how to write run-length encoding as a fold on lists.
-
Friday, 2nd February 2001
-
Richard introduced the Burrows-Wheeler transform on strings, which
groups together multiple occurrences of the same letter in order to
aid compression. He explained a simple algorithm to invert the
transform (not an application of the converse function theorem)
but why it worked was a mystery.
Jeremy gave an iff condition for when a function can be expressed
as a fold. It used the concept of the kernel of a function: the set
of pairs of elements on which the function has the same output.
Although he couldn't see how to adapt his working from functions to
relations, he attempted a diagram-chasing categorical proof of the
"iff", observing that kernels are equivalent to pullbacks for those
categories that have them.
Barney Stratford
(Barney.Stratford@comlab.ox.ac.uk),
from October 26th
Ian Bayley
(Ian.Bayley@comlab.ox.ac.uk),
until October 19th
Shin-Cheng Mu
(Shin-Cheng.Mu@comlab.ox.ac.uk),
20th April 2001 and 8th May only
|
|