Zulip Chat Archive

Stream: Is there code for X?

Topic: proofs about for loops


Scott Morrison (Sep 13 2023 at 02:54):

Does anyone have advice about how to proceed with problems like:

def eval (a : Nat) (B C : Array Nat) : Nat := Id.run do
  let mut r := a
  for b in B, c in C do
    r := r + b * c
  return r

def eval' (a : Nat) (B C : Array Nat) : Nat :=
  B.zip C |>.foldl (init := a) fun r b, c => r + b * c

example : eval a B C = eval' a B C := sorry

Presumably we will eventually have a library of lemmas about for loops that transform common idioms into the functional style.

But we don't have that yet, right?

What would you do if faced with this now?

Damiano Testa (Sep 13 2023 at 03:30):

Did you want eval' to take Int values? And B, C are Nats in eval and Ints in eval'?

Scott Morrison (Sep 13 2023 at 03:31):

Sorry, copy-paste errors! All just in Nat.

Damiano Testa (Sep 13 2023 at 03:33):

EDIT: ignore me -- I did not know what for b in B, c in C do meant
Also:

#eval
  let a := 1
  let B : Array Nat := #[1, 1]
  let C : Array Nat := #[1]
  let B' : Array Int := B.map fun x => (Nat.cast x : Int)
  let C' : Array Int := B.map fun x => (Nat.cast x : Int)
  eval a B C = eval' a B' C'

Damiano Testa (Sep 13 2023 at 03:33):

Should using B twice, instead of B and C be good?

Damiano Testa (Sep 13 2023 at 03:34):

(Note that I don't know that I'll be able to help with the proof, but I'm trying to understand at least the statement!)

Damiano Testa (Sep 13 2023 at 05:23):

I tried this a little, but failed. These are my thoughts -- they are certainly a subset of yours, but maybe it helps to see them written down!

  • Working with List rather than Array seems better for proofs. In particular, eval' for Lists (i.e. List.foldl) has already some API also for its TR version.
  • Even the version where you compare the List.foldl (· + ·) to the sum of a single list is a struggle!

That's all I have... :shrug:

Scott Morrison (Sep 13 2023 at 11:19):

Here's the prototypical example of "how do I prove things about for loops!?":

set_option autoImplicit true
set_option relaxedAutoImplicit true

example {a : α} {bs : Array β} :
    (Id.run do
      let mut r := a
      for b in bs do r := f r b
      return r) =
      bs.foldl f a :=
  sorry

Suggestions welcome!

Scott Morrison (Sep 13 2023 at 11:38):

I'm beginning to see how one would do this. We have things like docs#Array.SatisfiesM_foldlM already (heroic work by Mario!), but don't yet have a corresponding Array.SatisfiesM_forIn (not that I'm even sure what that would say!). But I think that would be the first step.

Patrick Massot (Sep 13 2023 at 12:29):

See the discussion at https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Proof.20of.20program

Scott Morrison (Sep 13 2023 at 12:46):

The key step in @Mario Carneiro's answer there unfortunately doesn't work with today's Std. I wonder if the "with some new lemmas in Std" that he referred to in that message didn't actually make it to Std. :-)

Mario Carneiro (Sep 13 2023 at 18:59):

@Scott Morrison The new lemmas did make it to Std, but something seems to have broken the base case, List.range' isn't simplifying like it used to. This proof works:

import Std.Data.Range.Lemmas
import Std.Data.List.Lemmas

def sum (n : Nat) := Id.run do
  let mut r := 0
  for i in [0:n] do
    r := r + i
  return r

theorem sum_eq (n : Nat) : sum (n + 1) = n*(n+1)/2 := by
  suffices  l i acc r, l + i = n  i * (i + 1) = 2 * acc 
      Id.run (forIn (List.range' (i+1) l) acc fun i r => .yield (r + i)) = r 
      n * (n + 1) = 2 * r by
    rw [sum]
    simp [Std.Range.forIn_eq_forIn_range', Std.Range.numElems_step_1]
    refine (Nat.div_eq_of_eq_mul_right (by decide) ?_).symm
    exact this _ _ _ _ (by rfl) (by rfl) rfl
  intro l i acc r e ih hr
  induction l generalizing i acc
  · simp [ e, ih,  hr, forIn, Id.run]; simp [List.range']
  · next l IH =>
    rw [Nat.succ_add] at e
    refine IH i.succ _ e ?_ hr
    rw [Nat.mul_add 2,  ih,  Nat.add_mul, Nat.mul_comm]

Mario Carneiro (Sep 13 2023 at 19:01):

the "new lemma" in question is Std.Range.forIn_eq_forIn_range'


Last updated: Dec 20 2023 at 11:08 UTC