Live data from Hacker News

Verified dynamic programming with Σ-types in Lean

tannerduve.github.io

41–46 of 46 posts

Re: Verified dynamic programming with Σ-types in Lean

#41

This is proof by exhaustion: the "proof" just computes the entire memo table for any n and compares the values in the table with the corresponding return from recursive definition. You could write this same proof in absolutely any language that supports recursion (or not, if you transform to the bottom-up formulation).

> You could write this same proof in absolutely any language that supports recursion

Well, you at least need dependent types just to state the theorem, which eliminates nearly all other languages.

Re: Verified dynamic programming with Σ-types in Lean

#42

Really interesting trick!

He doesn't mention it, but this is a form of proof by induction. (As you'd expect, really, for a universal statement.) Induction is often taught as something you do with natural numbers. But it's actually something you do with sets that are defined inductively. Any time you have a set that is defined like so: 1. x is in the set. 2. for all y in the set, f(y) is in the set (where x and f are constants), you can apply…

Great breakdown of this. Thanks.

Re: Verified dynamic programming with Σ-types in Lean

#43
post #32

This would be the classical proof via strong induction, without Σ-types: https://live.lean-lang.org/#codez=JYWwDg9gTgLgBAZRgEwHQBECGN... Doing the proof inside the algorithm (i.e. doing inline induction over the algorithm recursion structure) has the advantage that the branching structure doesn't have to be duplicated as in an external proof like the one I did. In my proof I didn't struggle so much with induction, bu…

Nice job. My attempt at the initial strong induction proof was a long time ago so I don't remember the details. It definitely followed a similar structure as yours (but this was before `omega` im pretty sure). Can't quite remember where I got stuck but your proof is good. Thanks!

Re: Verified dynamic programming with Σ-types in Lean

#44

Earlier quoted context omitted.

> I didn't say the lean code doesn't prove equality, I said it proves it using exhaustion. What is exhaustion for you? For everyone else in this thread, exhaustion means trying out all values and proving it works. Exhaustive proof: pick 64-bits for a bit trick, run inefficient algorithm and get 64-bit outputs for all 2^64 bitsets, and then run the bit trick algorithm and exhaustively prove slow(n)==bittrick(n) for al…

> For everyone else in this thread, exhaustion means trying out all values and proving it works. My instinct was that you can still call it proof by exhaustion if you divide the values into classes and do the proof for each class. > Similar way you'd prove four color theorem. And this seems to support that idea? It's the same thing as proof by cases. So the proof that n^2 + n is even for all integers is exhaustive: y…

Thing with "classes" is that you need to identify them before proving and you need to prove the implication to general case.

Lean is not powerful enough to do this, to somehow conclude that there's a finite set of cases on which you can run brute-force checks and prove a general case.

Re: Verified dynamic programming with Σ-types in Lean

#45

I've been meaning to learn Lean and fascinated with the concept but syntax like: let rec helperMemo : Nat → HashMap Nat Nat → Nat × HashMap Nat Nat is a big turnoff to me. I find it annoying to parse mentally. I can do it but I have to concentrate or it's easy to gloss over an important detail.

Tbh this is exactly how I felt in my algebraic geometry class. I still remember the fear I had when reading this from the blackboard

    Defn. f: X → Y is flat ⇔ O_{Y,f(x)} → O_{X,x} flat ∀ x.
Then immediately I dropped that class. Turns out I like real analysis much more

Re: Verified dynamic programming with Σ-types in Lean

#46

Earlier quoted context omitted.

> the "proof" just computes the entire memo table for any n No, this is what would happen _if you ran the proof_, but proofs are not meant to be ran in the first place! The usual goal is proving their correctness, and for that it's enough for them to _typecheck_.

it's explicitly stated in the article: > For an arbitrary n, compute the table full of values and their proofs, and just pull out the nth proof if you thought harder about it you'd realize what you're suggesting is impossible

> it's explicitly stated in the article: > > > For an arbitrary n, compute the table full of values and their proofs, and just pull out the nth proof

That's what the intermediate function is doing, but _it doesn't need to be executed_ for the final proof to be valid.

> if you thought harder about it you'd realize what you're suggesting is impossible

No, it is perfectly possible. This is not a program running all cases and `assert`ing that they have the expected result, this is a proof encoded as a program that when executed will surely produce a proof that for the given n the theorem holds. But it surely produces a proof when executes you don't need to execute it to know that a proof exists and thus the theorem holds!

This is exactly what mathematicians do when they prove theorems. Do you think they go on and check for every number n that some theorem holds? That's impossible to do for every possible n, and this is exactly what you're claiming you can do in every other language.

And just to be extra clear, a signature like this:

> theorem maxDollars_spec_correct : ∀ n, maxDollars n = maxDollars_spec n

Does not mean that for every n the function returns a boolean indicating whether `maxDollars n` is equal to `maxDollars_spec n` or not. Instead, it _surely_ returns a proof that they are equal. And with _surely_ I mean it cannot return errors or exceptions or whatever. It is guaranteed that the function will terminate with a proof for that proposition, which I want to reiterate again, it's the same as knowing that the proposition is true.

Post reply on HN