Zulip Chat Archive

Stream: new members

Topic: proof about recursive function


Somo S. (Oct 11 2023 at 15:22):

Hi, I am having some trouble reasoning about a recursive function I wrote. I am realizing that maybe my understanding about recursive function proofs is lacking in general. So I have put together a little example adapted from FPIL, with the hope that someone can show me how one goes about this kind of thing:

namespace mydiv

def div (n k : Nat) (ok : k > 0) : Nat :=
  if h : n < k then
    0
  else
    1 + div (n - k) k ok
decreasing_by sorry -- skip: already proved

theorem foo (n k : Nat) (ok : k > 0) : div n k ok  n := sorry -- NEED HELP
end mydiv

Somo S. (Oct 11 2023 at 15:27):

I do see that Nat.div_le_self is a similar theorem that's already proved but I dont understand it. Dont understand using Nat.strongInductionOn, the ind n ih or the cases (inferInstance : Decidable (0 < k ∧ k ≤ n)) terms

Somo S. (Oct 11 2023 at 15:30):

so I'd rather focus on elementary technique for solving the above example (from scratch or "as scratch as is reasonable").. with the hope that I can generalize this to what I'm actually working on

Ruben Van de Velde (Oct 11 2023 at 15:33):

I came up with

theorem foo (n k : Nat) (ok : k > 0) : div n k ok  n := by
  unfold div
  split_ifs with h
  · apply Nat.zero_le
  · simp at h
    have := foo (n - k) k ok
    rw [Nat.le_sub_iff_add_le h] at this
    apply le_trans ?_ this
    rw [add_comm]
    gcongr
    rwa [Nat.succ_le]

but it doesn't pass termination checking

Somo S. (Oct 11 2023 at 15:38):

Somo S. said:

so I'd rather focus on elementary technique for solving the above example (from scratch or "as scratch as is reasonable").. with the hope that I can generalize this to what I'm actually working on

thanks @Ruben Van de Velde .. actually, I'd like to avoid mathlib tactics. I dont want to depend on mathlib in my actual project if i can help it

Ruben Van de Velde (Oct 11 2023 at 15:42):

If you mean gcongr, I replaced that by show_term gcongr which tells me Try this: refine add_le_add_left ?bc (div (n - k) k ok)

Ruben Van de Velde (Oct 11 2023 at 15:43):

I suppose there are ways to avoid split_ifs as well

Somo S. (Oct 11 2023 at 15:43):

yes and split_ifs, rwa

Somo S. (Oct 11 2023 at 15:43):

okay I will try the strategy of using show_term to get equivalents..

Ruben Van de Velde (Oct 11 2023 at 15:44):

rwa is from Std

Somo S. (Oct 11 2023 at 15:44):

also can you explain what ?_ does.. I am familiar with _ but not ?_

Ruben Van de Velde (Oct 11 2023 at 15:45):

But this is closer to mathlib-free:

theorem foo (n k : Nat) (ok : k > 0) : div n k ok  n := by
  unfold div
  split_ifs with h
  · apply Nat.zero_le
  · simp only [Nat.not_lt] at h
    have := foo (n - k) k ok
    rw [Nat.le_sub_iff_add_le h] at this
    apply Nat.le_trans ?_ this
    rw [Nat.add_comm]
    refine Nat.add_le_add_left ?bc (div (n - k) k ok)
    rw [Nat.succ_le]
    assumption
decreasing_by sorry -- skip: already proved

(mostly using nat-specific lemmas rather than their generalizations)

Ruben Van de Velde (Oct 11 2023 at 15:45):

?_ means "create a new goal to fill this hole"

Somo S. (Oct 11 2023 at 15:48):

is split_ifs similar to by_cases ?

Ruben Van de Velde (Oct 11 2023 at 15:51):

split_ifs looks at the if expressions in the goal (in this case) and creates new goals for the positive and negative cases and replaces the if term by the relevant case

Somo S. (Oct 11 2023 at 15:52):

ok thanks. I will try to adapt this. Already useful to know I should have started by unfolding


Last updated: Dec 20 2023 at 11:08 UTC