/- Copyright (c) 2025 Lean FRO, LLC. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Paul Reichert -/ module prelude public import Std.Data.Iterators.Lemmas.Consumers.Collect import Std.Data.Iterators.Lemmas.Consumers.Loop import Init.Data.List.TakeDrop public import Std.Data.Iterators.Producers.Array public import Init.Data.Iterators.Producers.List public import Std.Data.Iterators.Lemmas.Producers.Monadic.Array @[expose] public section /-! # Lemmas about array iterators This module provides lemmas about the interactions of `Array.iter` with `Iter.step` and various collectors. -/ open Std Std.Iterators variable {β : Type w} theorem Array.iter_eq_toIter_iterM {array : Array β} : array.iter = (array.iterM Id).toIter := rfl theorem Array.iter_eq_iterFromIdx {array : Array β} : array.iter = array.iterFromIdx 0 := rfl theorem Array.iterFromIdx_eq_toIter_iterFromIdxM {array : Array β} {pos : Nat} : array.iterFromIdx pos = (array.iterFromIdxM Id pos).toIter := rfl theorem Array.step_iterFromIdx {array : Array β} {pos : Nat} : (array.iterFromIdx pos).step = if h : pos < array.size then .yield (array.iterFromIdx (pos + 1)) array[pos] ⟨rfl, rfl, h, rfl⟩ else .done (Nat.not_lt.mp h) := by simp only [Array.iterFromIdx_eq_toIter_iterFromIdxM, Iter.step, Iter.toIterM_toIter, Array.step_iterFromIdxM, Id.run_pure, Shrink.inflate_deflate] split <;> rfl theorem Array.step_iter {array : Array β} : array.iter.step = if h : 0 < array.size then .yield (array.iterFromIdx 1) array[0] ⟨rfl, rfl, h, rfl⟩ else .done (Nat.not_lt.mp h) := by simp only [Array.iter_eq_iterFromIdx, Array.step_iterFromIdx] @[simp, grind =] theorem Array.toList_iterFromIdx {array : Array β} {pos : Nat} : (array.iterFromIdx pos).toList = array.toList.drop pos := by simp [Iter.toList, Array.iterFromIdx_eq_toIter_iterFromIdxM, Iter.toIterM_toIter, Array.toList_iterFromIdxM] @[simp, grind =] theorem Array.toList_iter {array : Array β} : array.iter.toList = array.toList := by simp [Array.iter_eq_iterFromIdx, Array.toList_iterFromIdx] @[simp, grind =] theorem Array.toArray_iterFromIdx {array : Array β} {pos : Nat} : (array.iterFromIdx pos).toArray = array.extract pos := by simp [iterFromIdx_eq_toIter_iterFromIdxM, Iter.toArray] @[simp, grind =] theorem Array.toArray_iter {array : Array β} : array.iter.toArray = array := by simp [Array.iter_eq_iterFromIdx] @[simp, grind =] theorem Array.toListRev_iterFromIdx {array : Array β} {pos : Nat} : (array.iterFromIdx pos).toListRev = (array.toList.drop pos).reverse := by simp [Iter.toListRev_eq, Array.toList_iterFromIdx] @[simp, grind =] theorem Array.toListRev_iter {array : Array β} : array.iter.toListRev = array.toListRev := by simp [Array.iter_eq_iterFromIdx] @[simp, grind =] theorem Array.length_iterFromIdx {array : Array β} {pos : Nat} : (array.iterFromIdx pos).length = array.size - pos := by simp [← Iter.length_toList_eq_length] @[simp, grind =] theorem Array.length_iter {array : Array β} : array.iter.length = array.size := by simp [← Iter.length_toList_eq_length] section Equivalence theorem Array.iterFromIdx_equiv_iter_drop_toList {α : Type w} {array : Array α} {pos : Nat} : (array.iterFromIdx pos).Equiv (array.toList.drop pos).iter := by apply IterM.Equiv.toIter exact Array.iterFromIdxM_equiv_iterM_drop_toList theorem Array.iter_equiv_iter_toList {α : Type w} {array : Array α} : array.iter.Equiv array.toList.iter := by rw [Array.iter_eq_iterFromIdx] simpa using iterFromIdx_equiv_iter_drop_toList end Equivalence