Research
λ calculus Agda Bidirectional Updating Burrows-Wheeler Transform Concurrency Converse-of-a-Function Theorem Curry-Howard Data Structure Dependent Type Fibonacci GADT Greedy Theorem Haskell HaXML List Homomorphism Logic Logic Programming Program Derivation Program Inversion Quantum Programming Quine Regular Expression Segment Problems Termination Thinning Theorem Types XML Streaming-
Recent Comments
On a Basic Property for the Longest Prefix Problem
In the Software Construction course next week we will, inevitably, talk about maximum segment sum. A natural next step is to continue with the theme of segment problems, which doesn’t feel complete without mentioning Hans Zantema’s Longest Segment Problems.
The paper deals with problem of this form:
That is, computing the longest consecutive segment of the input list that satisfies predicate
p. When writing on paper I found it much easier denotingfilter pby the Bird-Meertens stylep ◁and I will use the latter for this post too. The functionsegs :: [a] → [[a]], defined bysegs = concat ∘ map inits ∘ tailsreturns all consecutive segments of the input list, andmax# :: [[a]] → [a]returns the longest list from the input list of lists. To avoid long nesting parenthesis, I denote function application by an infix operator▪that binds looser than function composition∘. Thereforef ∘ g ∘ h ▪ xmeansf (g (h x)).Standard transformation turns the specification to the form
Therefore we may solve
lsif we manage to solve its sub-problem on prefixes:that is, computing the longest prefix of the input list satisfying predicate
p. One of the key propositions in the paper says:It is useful because, by composing
max#on both sides we getthat is,
lpcan be computed by afoldr.Of course, we are not quite done yet. We then have to somehow simplify
p ◁ ∘ inits ▪ (a : lp x)to something more efficient. Before we move on, however, proving Proposition 1 turns out to be an interesting challenge in itself.Intuition
What does Proposition 1 actually say? Let
x = [1,2,3]anda = 0. On the left-hand side, we are performingp ◁onThe right hand side says that we may first filter the tails of
[1,2,3]:Assuming that only
[]and[1,2]get chosen. We may then keep the longest prefix[1,2]only, generate all its prefixes (which would be[] [1] [1,2]), and filter the latter again. In other words, we lost no information dropping[1,2,3]if it fails predicatep, since by suffix-closure,p ([0] ⧺ [1,2,3]) ⇒ p [1,2,3]. If[1,2,3]doesn’t passp,p [0,1,2,3]cannot be true either.Zantema has a nice and brief proof of Proposition 1 by contradiction. However, the theme of this course has mainly focused on proof by induction and, to keep the possibility of someday encoding our derivations in tools like Coq or Agda, we would like to have a constructive proof.
So, is it possible to prove Proposition 1 in a constructive manner?
The Proof
I managed to come up with a proof. I’d be happy to know if there is a better way, however.
For brevity, I denote
if p then x else ybyp → x; y. Also, defineTherefore
p ◁is defined byHere comes the the main proof:
Proposition 1
if
pis suffix-closed.Proof.
∎
The main proof refers to two “decomposition” lemmas, both are of the form
f ∘ g = f ∘ g ∘ f:p ◁ ∘ map (a:) = p ◁ ∘ map (a:) ∘ p ◁ifpsuffix-closed.p ◁ ∘ inits ∘ max# ∘ p ◁ ∘ inits = p ◁ ∘ initsfor all predicatep.Both are proved by structural induction. For Lemma 1 we need the conditional distribution rule:
If we are working in CPO we need the side condition that
fis strict, which is true for the cases below anyway:Lemma 1
if
pis suffix-closed.Proof. Structural induction on the input.
Case []: trivial.
Case (x : xs):
∎
For Lemma 2, it is important that
pis universally quantified. We need the following map-filter exchange rule:The proof goes:
Lemma 2 For all predicate
pwe haveProof. Structural induction on the input.
Case []: trivial.
Case (a : x):
Consider two cases:
1. Case
p [] ∧ null (p ◁ ∘ map (a :) ∘ inits ▪ x):If
¬ p [], both sides are undefined. Otherwise:2. Case
¬ (null (p ◁ ∘ map (a :) ∘ inits ▪ x)):∎
Reference