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 mvcgen and my function is based on Rco

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