Zulip Chat Archive
Stream: Is there code for X?
Topic: proving about `Rco`
Asei Inoue (Nov 18 2025 at 12:54):
how to show this?
theorem lem (n : Nat) : (0...n).toList = List.range n := by
sorry
Asei Inoue (Nov 18 2025 at 12:58):
Background: I want to construct a proof by using mvcgen and my function is based on Rco
Ruben Van de Velde (Nov 18 2025 at 13:33):
Obviously (obviously) like this:
theorem lem (n : Nat) : (0...n).toList = List.range n := by
induction n with
| zero => simp only [Std.Rco.toList_eq_if, Nat.lt_irrefl, ↓reduceIte, List.range_zero]
| succ n ih =>
simp only [Std.Rco.toList_eq_if, Nat.zero_lt_succ, ↓reduceIte, List.range_succ_eq_map,
List.cons.injEq, true_and]
rw [← ih]
rw [← Std.PRange.Nat.toList_Rco_succ_succ]
simp only [Nat.zero_add]
rw [Std.toList_Roo_eq_toList_Rco_of_isSome_succ? Std.PRange.isSome_succ?]
simp [Std.PRange.Nat.succ_eq]
Ruben Van de Velde (Nov 18 2025 at 13:33):
I conclude there is significant missing API
Paul Reichert (Nov 18 2025 at 14:08):
How does the function (or for...in construct) look on which you applied mvcgen?
Asei Inoue (Nov 18 2025 at 14:10):
(deleted)
Asei Inoue (Nov 18 2025 at 14:12):
here is my code
import Lean
import Batteries
open Std Do
variable {α : Type} [LE α] [LT α]
variable [DecidableLE α] [DecidableLT α]
variable [IsLinearOrder α] [LawfulOrderLT α]
def Array.isSorted (l : Array α) : Bool := Id.run do
let n := l.size
for h : i in (0...n-1) do
if l[i] > l[i + 1] then
return false
return true
set_option mvcgen.warning false
theorem Array.isSorted_spec (l : Array α) :
l.isSorted ↔ l.Pairwise (· ≤ ·) := by
generalize h : l.isSorted = r
apply Id.of_wp_run_eq h
mvcgen invariants
· Invariant.withEarlyReturn
(onContinue := fun cursor _ => ⌜l.take (cursor.pos + 1) |>.Pairwise (· ≤ ·)⌝)
(onReturn := fun ret _ => ⌜ret = false ∧ ¬ l.Pairwise (· ≤ ·)⌝)
case vc1 =>
sorry
all_goals sorry
Paul Reichert (Nov 18 2025 at 14:19):
Thanks! I am working on adding the lemmas for the new ranges and slices to the API until the end of this year. Proving things about range-based loops will get more comfortable, but for now, Ruben Van de Velde's lemma is probably the best way for you to deal with this.
Ruben Van de Velde (Nov 18 2025 at 15:07):
Shorter:
@[simp]
theorem aux0 (n k : Nat) : Std.PRange.succMany? n k = k + n := by
simp [Std.PRange.succMany?]
theorem aux6 (m n i : Nat) : (m...n).toList[i]? = if i < n - m then some (m + i) else none := by
simp [Std.Rco.getElem?_toList_eq]
grind
theorem lem (n : Nat) : (0...n).toList = List.range n := by
ext i x
rw [aux6]
grind [List.getElem?_range]
Ruben Van de Velde (Nov 18 2025 at 15:08):
More code if you're interested
Asei Inoue (Nov 23 2025 at 15:09):
I want to construct a proof by using
mvcgenand my function is based onRco
I have done! Thank you!!
import Std.Tactic.Do
import Batteries.Data.Array
open Std
variable {α : Type} [LT α] [DecidableLT α]
def Array.isSorted (arr : Array α) : Bool := Id.run do
let n := arr.size
for h : i in (0...n-1) do
if arr[i] > arr[i + 1] then
return false
return true
open Std.Do
set_option mvcgen.warning false
namespace Std
@[simp]
theorem PRange.succMany?_spec (n k : Nat) : PRange.succMany? n k = k + n := by
simp [PRange.succMany?]
theorem Rco.toList_getElem? (m n i : Nat)
: (m...n).toList[i]? = if i < n - m then some (m + i) else none := by
simp [Rco.getElem?_toList_eq]
grind
@[simp]
theorem Rco.toList_eq {n : Nat} : (0...n).toList = List.range n := by
ext i x
rw [Rco.toList_getElem?]
grind [List.getElem?_range]
@[simp]
theorem Range.toList_eq {n : Nat} : [0:n].toList = List.range n := by
ext i x
grind
@[grind =]
theorem Rco_eq_Range_of_toList {n : Nat} : (0...n).toList = [0:n].toList := by
simp
end Std
@[grind <=]
theorem Array.not_pairwise_of_succ_pair {α : Type} (arr : Array α) {R : α → α → Prop} (i : Nat)
(hi : i + 1 < arr.size) (h : ¬ R arr[i] arr[i + 1])
: ¬Pairwise R arr := by
simp [Array.pairwise_iff_getElem]
grind
@[grind <=]
theorem Array.sorted_take_cons_cons {α : Type} [LE α] [IsPreorder α] (arr : Array α)
(i : Nat) (hi : i + 1 < arr.size) (harr : arr[i] ≤ arr[i + 1])
(h : Pairwise (· ≤ ·) (arr.take (i + 1)))
: Pairwise (· ≤ ·) (arr.take (i + 1 + 1)) := by
simp [Array.pairwise_iff_getElem] at *
grind
@[grind <=]
theorem Array.pairwise_subsingleton {α : Type} {R : α → α → Prop} {arr : Array α}
(h : arr.size ≤ 1) : Pairwise R arr := by
simp [Array.pairwise_iff_getElem] at *
grind
@[grind =]
theorem Array.Grind.extract_all {α : Type} (arr : Array α) (n : Nat) (h : n = arr.size)
: arr.extract 0 n = arr := by
grind
variable [LE α] [IsLinearOrder α] [LawfulOrderLT α]
theorem Array.isSorted_spec (arr : Array α) :
arr.isSorted = true ↔ arr.Pairwise (· ≤ ·) := by
generalize h : arr.isSorted = r
apply Id.of_wp_run_eq h
mvcgen invariants
· Invariant.withEarlyReturn
(onContinue := fun cursor _ => ⌜arr.take (cursor.pos + 1) |>.Pairwise (· ≤ ·)⌝)
(onReturn := fun ret _ => ⌜ret = false ∧ ¬ arr.Pairwise (· ≤ ·)⌝)
with (simp at *; grind)
Paul Reichert (Dec 02 2025 at 17:30):
lean#11321 #11321 is going to add a lot of lemmas about Std.Rco specialized to Nat. It also adds a lemma List.range_eq_toList_rco that does what you were asking for, but the API support for Rco is better than for List.range with this PR, so you hopefully won't need to rewrite to List.range anymore.
Asei Inoue (Dec 02 2025 at 20:07):
you mean lean4#11321?
Paul Reichert (Dec 02 2025 at 20:32):
Yes, that's the one I meant. Thanks.
Last updated: Dec 20 2025 at 21:32 UTC