1021 lines
36 KiB
Text
1021 lines
36 KiB
Text
/-
|
||
Copyright (c) 2018 Microsoft Corporation. All rights reserved.
|
||
Released under Apache 2.0 license as described in the file LICENSE.
|
||
Authors: Leonardo de Moura
|
||
-/
|
||
prelude
|
||
import Init.WFTactics
|
||
import Init.Data.Nat.Basic
|
||
import Init.Data.Fin.Basic
|
||
import Init.Data.UInt.BasicAux
|
||
import Init.Data.Repr
|
||
import Init.Data.ToString.Basic
|
||
import Init.GetElem
|
||
import Init.Data.List.ToArrayImpl
|
||
import Init.Data.Array.Set
|
||
|
||
universe u v w
|
||
|
||
/-! ### Array literal syntax -/
|
||
|
||
syntax "#[" withoutPosition(sepBy(term, ", ")) "]" : term
|
||
|
||
macro_rules
|
||
| `(#[ $elems,* ]) => `(List.toArray [ $elems,* ])
|
||
|
||
variable {α : Type u}
|
||
|
||
namespace Array
|
||
|
||
@[deprecated toList (since := "2024-10-13")] abbrev data := @toList
|
||
|
||
/-! ### Preliminary theorems -/
|
||
|
||
@[simp] theorem size_set (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
|
||
(set a i v h).size = a.size :=
|
||
List.length_set ..
|
||
|
||
@[simp] theorem size_push (a : Array α) (v : α) : (push a v).size = a.size + 1 :=
|
||
List.length_concat ..
|
||
|
||
theorem ext (a b : Array α)
|
||
(h₁ : a.size = b.size)
|
||
(h₂ : (i : Nat) → (hi₁ : i < a.size) → (hi₂ : i < b.size) → a[i] = b[i])
|
||
: a = b := by
|
||
let rec extAux (a b : List α)
|
||
(h₁ : a.length = b.length)
|
||
(h₂ : (i : Nat) → (hi₁ : i < a.length) → (hi₂ : i < b.length) → a.get ⟨i, hi₁⟩ = b.get ⟨i, hi₂⟩)
|
||
: a = b := by
|
||
induction a generalizing b with
|
||
| nil =>
|
||
cases b with
|
||
| nil => rfl
|
||
| cons b bs => rw [List.length_cons] at h₁; injection h₁
|
||
| cons a as ih =>
|
||
cases b with
|
||
| nil => rw [List.length_cons] at h₁; injection h₁
|
||
| cons b bs =>
|
||
have hz₁ : 0 < (a::as).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
|
||
have hz₂ : 0 < (b::bs).length := by rw [List.length_cons]; apply Nat.zero_lt_succ
|
||
have headEq : a = b := h₂ 0 hz₁ hz₂
|
||
have h₁' : as.length = bs.length := by rw [List.length_cons, List.length_cons] at h₁; injection h₁
|
||
have h₂' : (i : Nat) → (hi₁ : i < as.length) → (hi₂ : i < bs.length) → as.get ⟨i, hi₁⟩ = bs.get ⟨i, hi₂⟩ := by
|
||
intro i hi₁ hi₂
|
||
have hi₁' : i+1 < (a::as).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
|
||
have hi₂' : i+1 < (b::bs).length := by rw [List.length_cons]; apply Nat.succ_lt_succ; assumption
|
||
have : (a::as).get ⟨i+1, hi₁'⟩ = (b::bs).get ⟨i+1, hi₂'⟩ := h₂ (i+1) hi₁' hi₂'
|
||
apply this
|
||
have tailEq : as = bs := ih bs h₁' h₂'
|
||
rw [headEq, tailEq]
|
||
cases a; cases b
|
||
apply congrArg
|
||
apply extAux
|
||
assumption
|
||
assumption
|
||
|
||
theorem ext' {as bs : Array α} (h : as.toList = bs.toList) : as = bs := by
|
||
cases as; cases bs; simp at h; rw [h]
|
||
|
||
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).toList = acc.toList ++ as := by
|
||
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
|
||
|
||
-- This does not need to be a simp lemma, as already after the `whnfR` the right hand side is `as`.
|
||
theorem toList_toArray (as : List α) : as.toArray.toList = as := rfl
|
||
|
||
@[simp] theorem size_toArray (as : List α) : as.toArray.size = as.length := by simp [size]
|
||
|
||
@[simp] theorem getElem_toList {a : Array α} {i : Nat} (h : i < a.size) : a.toList[i] = a[i] := rfl
|
||
|
||
@[simp] theorem getElem?_toList {a : Array α} {i : Nat} : a.toList[i]? = a[i]? := rfl
|
||
|
||
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
|
||
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
||
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
||
structure Mem (as : Array α) (a : α) : Prop where
|
||
val : a ∈ as.toList
|
||
|
||
instance : Membership α (Array α) where
|
||
mem := Mem
|
||
|
||
theorem mem_def {a : α} {as : Array α} : a ∈ as ↔ a ∈ as.toList :=
|
||
⟨fun | .mk h => h, Array.Mem.mk⟩
|
||
|
||
@[simp] theorem mem_toArray {a : α} {l : List α} : a ∈ l.toArray ↔ a ∈ l := by
|
||
simp [mem_def]
|
||
|
||
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] ∈ l := by
|
||
rw [Array.mem_def, ← getElem_toList]
|
||
apply List.getElem_mem
|
||
|
||
end Array
|
||
|
||
namespace List
|
||
|
||
@[simp] theorem toArray_toList (a : Array α) : a.toList.toArray = a := rfl
|
||
|
||
@[simp] theorem getElem_toArray {a : List α} {i : Nat} (h : i < a.toArray.size) :
|
||
a.toArray[i] = a[i]'(by simpa using h) := rfl
|
||
|
||
@[simp] theorem getElem?_toArray {a : List α} {i : Nat} : a.toArray[i]? = a[i]? := rfl
|
||
|
||
@[simp] theorem getElem!_toArray [Inhabited α] {a : List α} {i : Nat} :
|
||
a.toArray[i]! = a[i]! := rfl
|
||
|
||
end List
|
||
|
||
namespace Array
|
||
|
||
@[deprecated toList_toArray (since := "2024-09-09")] abbrev data_toArray := @toList_toArray
|
||
|
||
@[deprecated Array.toList (since := "2024-09-10")] abbrev Array.data := @Array.toList
|
||
|
||
/-! ### Externs -/
|
||
|
||
/-- Low-level version of `size` that directly queries the C array object cached size.
|
||
While this is not provable, `usize` always returns the exact size of the array since
|
||
the implementation only supports arrays of size less than `USize.size`.
|
||
-/
|
||
@[extern "lean_array_size", simp]
|
||
def usize (a : @& Array α) : USize := a.size.toUSize
|
||
|
||
/-- Low-level version of `fget` which is as fast as a C array read.
|
||
`Fin` values are represented as tag pointers in the Lean runtime. Thus,
|
||
`fget` may be slightly slower than `uget`. -/
|
||
@[extern "lean_array_uget", simp]
|
||
def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
||
a[i.toNat]
|
||
|
||
/-- Low-level version of `fset` which is as fast as a C array fset.
|
||
`Fin` values are represented as tag pointers in the Lean runtime. Thus,
|
||
`fset` may be slightly slower than `uset`. -/
|
||
@[extern "lean_array_uset"]
|
||
def uset (a : Array α) (i : USize) (v : α) (h : i.toNat < a.size) : Array α :=
|
||
a.set i.toNat v h
|
||
|
||
@[extern "lean_array_pop"]
|
||
def pop (a : Array α) : Array α where
|
||
toList := a.toList.dropLast
|
||
|
||
@[simp] theorem size_pop (a : Array α) : a.pop.size = a.size - 1 := by
|
||
match a with
|
||
| ⟨[]⟩ => rfl
|
||
| ⟨a::as⟩ => simp [pop, Nat.succ_sub_succ_eq_sub, size]
|
||
|
||
@[extern "lean_mk_array"]
|
||
def mkArray {α : Type u} (n : Nat) (v : α) : Array α where
|
||
toList := List.replicate n v
|
||
|
||
/--
|
||
Swaps two entries in an array.
|
||
|
||
This will perform the update destructively provided that `a` has a reference
|
||
count of 1 when called.
|
||
-/
|
||
@[extern "lean_array_fswap"]
|
||
def swap (a : Array α) (i j : @& Nat) (hi : i < a.size := by get_elem_tactic) (hj : j < a.size := by get_elem_tactic) : Array α :=
|
||
let v₁ := a[i]
|
||
let v₂ := a[j]
|
||
let a' := a.set i v₂
|
||
a'.set j v₁ (Nat.lt_of_lt_of_eq hj (size_set a i v₂ _).symm)
|
||
|
||
@[simp] theorem size_swap (a : Array α) (i j : Nat) {hi hj} : (a.swap i j hi hj).size = a.size := by
|
||
show ((a.set i a[j]).set j a[i]
|
||
(Nat.lt_of_lt_of_eq hj (size_set a i a[j] _).symm)).size = a.size
|
||
rw [size_set, size_set]
|
||
|
||
/--
|
||
Swaps two entries in an array, or returns the array unchanged if either index is out of bounds.
|
||
|
||
This will perform the update destructively provided that `a` has a reference
|
||
count of 1 when called.
|
||
-/
|
||
@[extern "lean_array_swap"]
|
||
def swapIfInBounds (a : Array α) (i j : @& Nat) : Array α :=
|
||
if h₁ : i < a.size then
|
||
if h₂ : j < a.size then swap a i j
|
||
else a
|
||
else a
|
||
|
||
@[deprecated swapIfInBounds (since := "2024-11-24")] abbrev swap! := @swapIfInBounds
|
||
|
||
/-! ### GetElem instance for `USize`, backed by `uget` -/
|
||
|
||
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||
getElem xs i h := xs.uget i h
|
||
|
||
/-! ### Definitions -/
|
||
|
||
instance : EmptyCollection (Array α) := ⟨Array.empty⟩
|
||
instance : Inhabited (Array α) where
|
||
default := Array.empty
|
||
|
||
def isEmpty (a : Array α) : Bool :=
|
||
a.size = 0
|
||
|
||
@[specialize]
|
||
def isEqvAux (a b : Array α) (hsz : a.size = b.size) (p : α → α → Bool) :
|
||
∀ (i : Nat) (_ : i ≤ a.size), Bool
|
||
| 0, _ => true
|
||
| i+1, h =>
|
||
p a[i] (b[i]'(hsz ▸ h)) && isEqvAux a b hsz p i (Nat.le_trans (Nat.le_add_right i 1) h)
|
||
|
||
@[inline] def isEqv (a b : Array α) (p : α → α → Bool) : Bool :=
|
||
if h : a.size = b.size then
|
||
isEqvAux a b h p a.size (Nat.le_refl a.size)
|
||
else
|
||
false
|
||
|
||
instance [BEq α] : BEq (Array α) :=
|
||
⟨fun a b => isEqv a b BEq.beq⟩
|
||
|
||
/--
|
||
`ofFn f` with `f : Fin n → α` returns the list whose ith element is `f i`.
|
||
```
|
||
ofFn f = #[f 0, f 1, ... , f(n - 1)]
|
||
``` -/
|
||
def ofFn {n} (f : Fin n → α) : Array α := go 0 (mkEmpty n) where
|
||
/-- Auxiliary for `ofFn`. `ofFn.go f i acc = acc ++ #[f i, ..., f(n - 1)]` -/
|
||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
go (i : Nat) (acc : Array α) : Array α :=
|
||
if h : i < n then go (i+1) (acc.push (f ⟨i, h⟩)) else acc
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
|
||
/-- The array `#[0, 1, ..., n - 1]`. -/
|
||
def range (n : Nat) : Array Nat :=
|
||
ofFn fun (i : Fin n) => i
|
||
|
||
@[inline] protected def singleton (v : α) : Array α := #[v]
|
||
|
||
def back! [Inhabited α] (a : Array α) : α :=
|
||
a[a.size - 1]!
|
||
|
||
@[deprecated back! (since := "2024-10-31")] abbrev back := @back!
|
||
|
||
def get? (a : Array α) (i : Nat) : Option α :=
|
||
if h : i < a.size then some a[i] else none
|
||
|
||
def back? (a : Array α) : Option α :=
|
||
a[a.size - 1]?
|
||
|
||
@[inline] def swapAt (a : Array α) (i : Nat) (v : α) (hi : i < a.size := by get_elem_tactic) : α × Array α :=
|
||
let e := a[i]
|
||
let a := a.set i v
|
||
(e, a)
|
||
|
||
@[inline]
|
||
def swapAt! (a : Array α) (i : Nat) (v : α) : α × Array α :=
|
||
if h : i < a.size then
|
||
swapAt a i v
|
||
else
|
||
have : Inhabited (α × Array α) := ⟨(v, a)⟩
|
||
panic! ("index " ++ toString i ++ " out of bounds")
|
||
|
||
/-- `take a n` returns the first `n` elements of `a`. -/
|
||
def take (a : Array α) (n : Nat) : Array α :=
|
||
let rec loop
|
||
| 0, a => a
|
||
| n+1, a => loop n a.pop
|
||
loop (a.size - n) a
|
||
|
||
@[deprecated take (since := "2024-10-22")] abbrev shrink := @take
|
||
|
||
@[inline]
|
||
unsafe def modifyMUnsafe [Monad m] (a : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
|
||
if h : i < a.size then
|
||
let v := a[i]
|
||
-- Replace a[i] by `box(0)`. This ensures that `v` remains unshared if possible.
|
||
-- Note: we assume that arrays have a uniform representation irrespective
|
||
-- of the element type, and that it is valid to store `box(0)` in any array.
|
||
let a' := a.set i (unsafeCast ())
|
||
let v ← f v
|
||
pure <| a'.set i v (Nat.lt_of_lt_of_eq h (size_set a ..).symm)
|
||
else
|
||
pure a
|
||
|
||
@[implemented_by modifyMUnsafe]
|
||
def modifyM [Monad m] (a : Array α) (i : Nat) (f : α → m α) : m (Array α) := do
|
||
if h : i < a.size then
|
||
let v := a[i]
|
||
let v ← f v
|
||
pure <| a.set i v
|
||
else
|
||
pure a
|
||
|
||
@[inline]
|
||
def modify (a : Array α) (i : Nat) (f : α → α) : Array α :=
|
||
Id.run <| modifyM a i f
|
||
|
||
@[inline]
|
||
def modifyOp (self : Array α) (idx : Nat) (f : α → α) : Array α :=
|
||
self.modify idx f
|
||
|
||
/--
|
||
We claim this unsafe implementation is correct because an array cannot have more than `usizeSz` elements in our runtime.
|
||
|
||
This kind of low level trick can be removed with a little bit of compiler support. For example, if the compiler simplifies `as.size < usizeSz` to true. -/
|
||
@[inline] unsafe def forIn'Unsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||
let sz := as.usize
|
||
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
||
if i < sz then
|
||
let a := as.uget i lcProof
|
||
match (← f a lcProof b) with
|
||
| ForInStep.done b => pure b
|
||
| ForInStep.yield b => loop (i+1) b
|
||
else
|
||
pure b
|
||
loop 0 b
|
||
|
||
/-- Reference implementation for `forIn'` -/
|
||
@[implemented_by Array.forIn'Unsafe]
|
||
protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||
let rec loop (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
|
||
match i, h with
|
||
| 0, _ => pure b
|
||
| i+1, h =>
|
||
have h' : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self i) h
|
||
have : as.size - 1 < as.size := Nat.sub_lt (Nat.zero_lt_of_lt h') (by decide)
|
||
have : as.size - 1 - i < as.size := Nat.lt_of_le_of_lt (Nat.sub_le (as.size - 1) i) this
|
||
match (← f as[as.size - 1 - i] (getElem_mem this) b) with
|
||
| ForInStep.done b => pure b
|
||
| ForInStep.yield b => loop i (Nat.le_of_lt h') b
|
||
loop as.size (Nat.le_refl _) b
|
||
|
||
instance : ForIn' m (Array α) α inferInstance where
|
||
forIn' := Array.forIn'
|
||
|
||
-- No separate `ForIn` instance is required because it can be derived from `ForIn'`.
|
||
|
||
/-- See comment at `forIn'Unsafe` -/
|
||
@[inline]
|
||
unsafe def foldlMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β → α → m β) (init : β) (as : Array α) (start := 0) (stop := as.size) : m β :=
|
||
let rec @[specialize] fold (i : USize) (stop : USize) (b : β) : m β := do
|
||
if i == stop then
|
||
pure b
|
||
else
|
||
fold (i+1) stop (← f b (as.uget i lcProof))
|
||
if start < stop then
|
||
if stop ≤ as.size then
|
||
fold (USize.ofNat start) (USize.ofNat stop) init
|
||
else
|
||
pure init
|
||
else
|
||
pure init
|
||
|
||
/-- Reference implementation for `foldlM` -/
|
||
@[implemented_by foldlMUnsafe]
|
||
def foldlM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β → α → m β) (init : β) (as : Array α) (start := 0) (stop := as.size) : m β :=
|
||
let fold (stop : Nat) (h : stop ≤ as.size) :=
|
||
let rec loop (i : Nat) (j : Nat) (b : β) : m β := do
|
||
if hlt : j < stop then
|
||
match i with
|
||
| 0 => pure b
|
||
| i'+1 =>
|
||
have : j < as.size := Nat.lt_of_lt_of_le hlt h
|
||
loop i' (j+1) (← f b as[j])
|
||
else
|
||
pure b
|
||
loop (stop - start) start init
|
||
if h : stop ≤ as.size then
|
||
fold stop h
|
||
else
|
||
fold as.size (Nat.le_refl _)
|
||
|
||
/-- See comment at `forIn'Unsafe` -/
|
||
@[inline]
|
||
unsafe def foldrMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → β → m β) (init : β) (as : Array α) (start := as.size) (stop := 0) : m β :=
|
||
let rec @[specialize] fold (i : USize) (stop : USize) (b : β) : m β := do
|
||
if i == stop then
|
||
pure b
|
||
else
|
||
fold (i-1) stop (← f (as.uget (i-1) lcProof) b)
|
||
if start ≤ as.size then
|
||
if stop < start then
|
||
fold (USize.ofNat start) (USize.ofNat stop) init
|
||
else
|
||
pure init
|
||
else if stop < as.size then
|
||
fold (USize.ofNat as.size) (USize.ofNat stop) init
|
||
else
|
||
pure init
|
||
|
||
/-- Reference implementation for `foldrM` -/
|
||
@[implemented_by foldrMUnsafe]
|
||
def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → β → m β) (init : β) (as : Array α) (start := as.size) (stop := 0) : m β :=
|
||
let rec fold (i : Nat) (h : i ≤ as.size) (b : β) : m β := do
|
||
if i == stop then
|
||
pure b
|
||
else match i, h with
|
||
| 0, _ => pure b
|
||
| i+1, h =>
|
||
have : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self _) h
|
||
fold i (Nat.le_of_lt this) (← f as[i] b)
|
||
if h : start ≤ as.size then
|
||
if stop < start then
|
||
fold start h init
|
||
else
|
||
pure init
|
||
else if stop < as.size then
|
||
fold as.size (Nat.le_refl _) init
|
||
else
|
||
pure init
|
||
|
||
/-- See comment at `forIn'Unsafe` -/
|
||
@[inline]
|
||
unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β) :=
|
||
let sz := as.usize
|
||
let rec @[specialize] map (i : USize) (r : Array NonScalar) : m (Array PNonScalar.{v}) := do
|
||
if i < sz then
|
||
let v := r.uget i lcProof
|
||
-- Replace r[i] by `box(0)`. This ensures that `v` remains unshared if possible.
|
||
-- Note: we assume that arrays have a uniform representation irrespective
|
||
-- of the element type, and that it is valid to store `box(0)` in any array.
|
||
let r := r.uset i default lcProof
|
||
let vNew ← f (unsafeCast v)
|
||
map (i+1) (r.uset i (unsafeCast vNew) lcProof)
|
||
else
|
||
pure (unsafeCast r)
|
||
unsafeCast <| map 0 (unsafeCast as)
|
||
|
||
/-- Reference implementation for `mapM` -/
|
||
@[implemented_by mapMUnsafe]
|
||
def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β) :=
|
||
-- Note: we cannot use `foldlM` here for the reference implementation because this calls
|
||
-- `bind` and `pure` too many times. (We are not assuming `m` is a `LawfulMonad`)
|
||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
map (i : Nat) (r : Array β) : m (Array β) := do
|
||
if hlt : i < as.size then
|
||
map (i+1) (r.push (← f as[i]))
|
||
else
|
||
pure r
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
map 0 (mkEmpty as.size)
|
||
|
||
@[deprecated mapM (since := "2024-11-11")] abbrev sequenceMap := @mapM
|
||
|
||
/-- Variant of `mapIdxM` which receives the index as a `Fin as.size`. -/
|
||
@[inline]
|
||
def mapFinIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||
(as : Array α) (f : Fin as.size → α → m β) : m (Array β) :=
|
||
let rec @[specialize] map (i : Nat) (j : Nat) (inv : i + j = as.size) (bs : Array β) : m (Array β) := do
|
||
match i, inv with
|
||
| 0, _ => pure bs
|
||
| i+1, inv =>
|
||
have j_lt : j < as.size := by
|
||
rw [← inv, Nat.add_assoc, Nat.add_comm 1 j, Nat.add_comm]
|
||
apply Nat.le_add_right
|
||
have : i + (j + 1) = as.size := by rw [← inv, Nat.add_comm j 1, Nat.add_assoc]
|
||
map i (j+1) this (bs.push (← f ⟨j, j_lt⟩ (as.get j j_lt)))
|
||
map as.size 0 rfl (mkEmpty as.size)
|
||
|
||
@[inline]
|
||
def mapIdxM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : Nat → α → m β) (as : Array α) : m (Array β) :=
|
||
as.mapFinIdxM fun i a => f i a
|
||
|
||
@[inline]
|
||
def findSomeM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) := do
|
||
for a in as do
|
||
match (← f a) with
|
||
| some b => return b
|
||
| _ => pure ⟨⟩
|
||
return none
|
||
|
||
/--
|
||
Note that the universe level is contrained to `Type` here,
|
||
to avoid having to have the predicate live in `p : α → m (ULift Bool)`.
|
||
-/
|
||
@[inline]
|
||
def findM? {α : Type} {m : Type → Type} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) := do
|
||
for a in as do
|
||
if (← p a) then
|
||
return a
|
||
return none
|
||
|
||
@[inline]
|
||
def findIdxM? [Monad m] (p : α → m Bool) (as : Array α) : m (Option Nat) := do
|
||
let mut i := 0
|
||
for a in as do
|
||
if (← p a) then
|
||
return some i
|
||
i := i + 1
|
||
return none
|
||
|
||
@[inline]
|
||
unsafe def anyMUnsafe {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) (start := 0) (stop := as.size) : m Bool :=
|
||
let rec @[specialize] any (i : USize) (stop : USize) : m Bool := do
|
||
if i == stop then
|
||
pure false
|
||
else
|
||
if (← p (as.uget i lcProof)) then
|
||
pure true
|
||
else
|
||
any (i+1) stop
|
||
if start < stop then
|
||
let stop' := min stop as.size
|
||
if start < stop' then
|
||
any (USize.ofNat start) (USize.ofNat stop')
|
||
else
|
||
pure false
|
||
else
|
||
pure false
|
||
|
||
@[implemented_by anyMUnsafe]
|
||
def anyM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) (start := 0) (stop := as.size) : m Bool :=
|
||
let any (stop : Nat) (h : stop ≤ as.size) :=
|
||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
loop (j : Nat) : m Bool := do
|
||
if hlt : j < stop then
|
||
have : j < as.size := Nat.lt_of_lt_of_le hlt h
|
||
if (← p as[j]) then
|
||
pure true
|
||
else
|
||
loop (j+1)
|
||
else
|
||
pure false
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
loop start
|
||
if h : stop ≤ as.size then
|
||
any stop h
|
||
else
|
||
any as.size (Nat.le_refl _)
|
||
|
||
@[inline]
|
||
def allM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) (start := 0) (stop := as.size) : m Bool :=
|
||
return !(← as.anyM (start := start) (stop := stop) fun v => return !(← p v))
|
||
|
||
@[inline]
|
||
def findSomeRevM? {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m (Option β)) (as : Array α) : m (Option β) :=
|
||
let rec @[specialize] find : (i : Nat) → i ≤ as.size → m (Option β)
|
||
| 0, _ => pure none
|
||
| i+1, h => do
|
||
have : i < as.size := Nat.lt_of_lt_of_le (Nat.lt_succ_self _) h
|
||
let r ← f as[i]
|
||
match r with
|
||
| some _ => pure r
|
||
| none =>
|
||
have : i ≤ as.size := Nat.le_of_lt this
|
||
find i this
|
||
find as.size (Nat.le_refl _)
|
||
|
||
@[inline]
|
||
def findRevM? {α : Type} {m : Type → Type w} [Monad m] (p : α → m Bool) (as : Array α) : m (Option α) :=
|
||
as.findSomeRevM? fun a => return if (← p a) then some a else none
|
||
|
||
@[inline]
|
||
def forM {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Array α) (start := 0) (stop := as.size) : m PUnit :=
|
||
as.foldlM (fun _ => f) ⟨⟩ start stop
|
||
|
||
@[inline]
|
||
def forRevM {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Array α) (start := as.size) (stop := 0) : m PUnit :=
|
||
as.foldrM (fun a _ => f a) ⟨⟩ start stop
|
||
|
||
@[inline]
|
||
def foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Array α) (start := 0) (stop := as.size) : β :=
|
||
Id.run <| as.foldlM f init start stop
|
||
|
||
@[inline]
|
||
def foldr {α : Type u} {β : Type v} (f : α → β → β) (init : β) (as : Array α) (start := as.size) (stop := 0) : β :=
|
||
Id.run <| as.foldrM f init start stop
|
||
|
||
@[inline]
|
||
def map {α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β :=
|
||
Id.run <| as.mapM f
|
||
|
||
/-- Variant of `mapIdx` which receives the index as a `Fin as.size`. -/
|
||
@[inline]
|
||
def mapFinIdx {α : Type u} {β : Type v} (as : Array α) (f : Fin as.size → α → β) : Array β :=
|
||
Id.run <| as.mapFinIdxM f
|
||
|
||
@[inline]
|
||
def mapIdx {α : Type u} {β : Type v} (f : Nat → α → β) (as : Array α) : Array β :=
|
||
Id.run <| as.mapIdxM f
|
||
|
||
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
|
||
def zipWithIndex (arr : Array α) : Array (α × Nat) :=
|
||
arr.mapIdx fun i a => (a, i)
|
||
|
||
@[inline]
|
||
def find? {α : Type u} (p : α → Bool) (as : Array α) : Option α :=
|
||
Id.run do
|
||
for a in as do
|
||
if p a then
|
||
return a
|
||
return none
|
||
|
||
@[inline]
|
||
def findSome? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||
Id.run <| as.findSomeM? f
|
||
|
||
@[inline]
|
||
def findSome! {α : Type u} {β : Type v} [Inhabited β] (f : α → Option β) (a : Array α) : β :=
|
||
match a.findSome? f with
|
||
| some b => b
|
||
| none => panic! "failed to find element"
|
||
|
||
@[inline]
|
||
def findSomeRev? {α : Type u} {β : Type v} (f : α → Option β) (as : Array α) : Option β :=
|
||
Id.run <| as.findSomeRevM? f
|
||
|
||
@[inline]
|
||
def findRev? {α : Type} (p : α → Bool) (as : Array α) : Option α :=
|
||
Id.run <| as.findRevM? p
|
||
|
||
@[inline]
|
||
def findIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option Nat :=
|
||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
loop (j : Nat) :=
|
||
if h : j < as.size then
|
||
if p as[j] then some j else loop (j + 1)
|
||
else none
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
loop 0
|
||
|
||
@[inline]
|
||
def findFinIdx? {α : Type u} (p : α → Bool) (as : Array α) : Option (Fin as.size) :=
|
||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
loop (j : Nat) :=
|
||
if h : j < as.size then
|
||
if p as[j] then some ⟨j, h⟩ else loop (j + 1)
|
||
else none
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
loop 0
|
||
|
||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size) :=
|
||
if h : i < a.size then
|
||
if a[i] == v then some ⟨i, h⟩
|
||
else indexOfAux a v (i+1)
|
||
else none
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
|
||
def indexOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
|
||
indexOfAux a v 0
|
||
|
||
@[deprecated indexOf? (since := "2024-11-20")]
|
||
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
|
||
a.findIdx? fun a => a == v
|
||
|
||
@[inline]
|
||
def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||
Id.run <| as.anyM p start stop
|
||
|
||
@[inline]
|
||
def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||
Id.run <| as.allM p start stop
|
||
|
||
/-- `as.contains a` is true if there is some element `b` in `as` such that `a == b`. -/
|
||
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
||
as.any (a == ·)
|
||
|
||
/--
|
||
Variant of `Array.contains` with arguments reversed.
|
||
|
||
For verification purposes, we simplify this to `contains`.
|
||
-/
|
||
def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
||
as.contains a
|
||
|
||
/-- Convert a `Array α` into an `List α`. This is O(n) in the size of the array. -/
|
||
-- This function is exported to C, where it is called by `Array.toList`
|
||
-- (the projection) to implement this functionality.
|
||
@[export lean_array_to_list_impl]
|
||
def toListImpl (as : Array α) : List α :=
|
||
as.foldr List.cons []
|
||
|
||
/-- Prepends an `Array α` onto the front of a list. Equivalent to `as.toList ++ l`. -/
|
||
@[inline]
|
||
def toListAppend (as : Array α) (l : List α) : List α :=
|
||
as.foldr List.cons l
|
||
|
||
protected def append (as : Array α) (bs : Array α) : Array α :=
|
||
bs.foldl (init := as) fun r v => r.push v
|
||
|
||
instance : Append (Array α) := ⟨Array.append⟩
|
||
|
||
protected def appendList (as : Array α) (bs : List α) : Array α :=
|
||
bs.foldl (init := as) fun r v => r.push v
|
||
|
||
instance : HAppend (Array α) (List α) (Array α) := ⟨Array.appendList⟩
|
||
|
||
@[inline]
|
||
def flatMapM [Monad m] (f : α → m (Array β)) (as : Array α) : m (Array β) :=
|
||
as.foldlM (init := empty) fun bs a => do return bs ++ (← f a)
|
||
|
||
@[deprecated flatMapM (since := "2024-10-16")] abbrev concatMapM := @flatMapM
|
||
|
||
@[inline]
|
||
def flatMap (f : α → Array β) (as : Array α) : Array β :=
|
||
as.foldl (init := empty) fun bs a => bs ++ f a
|
||
|
||
@[deprecated flatMap (since := "2024-10-16")] abbrev concatMap := @flatMap
|
||
|
||
/-- Joins array of array into a single array.
|
||
|
||
`flatten #[#[a₁, a₂, ⋯], #[b₁, b₂, ⋯], ⋯]` = `#[a₁, a₂, ⋯, b₁, b₂, ⋯]`
|
||
-/
|
||
@[inline] def flatten (as : Array (Array α)) : Array α :=
|
||
as.foldl (init := empty) fun r a => r ++ a
|
||
|
||
@[inline]
|
||
def filter (p : α → Bool) (as : Array α) (start := 0) (stop := as.size) : Array α :=
|
||
as.foldl (init := #[]) (start := start) (stop := stop) fun r a =>
|
||
if p a then r.push a else r
|
||
|
||
@[inline]
|
||
def filterM {α : Type} [Monad m] (p : α → m Bool) (as : Array α) (start := 0) (stop := as.size) : m (Array α) :=
|
||
as.foldlM (init := #[]) (start := start) (stop := stop) fun r a => do
|
||
if (← p a) then return r.push a else return r
|
||
|
||
@[specialize]
|
||
def filterMapM [Monad m] (f : α → m (Option β)) (as : Array α) (start := 0) (stop := as.size) : m (Array β) :=
|
||
as.foldlM (init := #[]) (start := start) (stop := stop) fun bs a => do
|
||
match (← f a) with
|
||
| some b => pure (bs.push b)
|
||
| none => pure bs
|
||
|
||
@[inline]
|
||
def filterMap (f : α → Option β) (as : Array α) (start := 0) (stop := as.size) : Array β :=
|
||
Id.run <| as.filterMapM f (start := start) (stop := stop)
|
||
|
||
@[specialize]
|
||
def getMax? (as : Array α) (lt : α → α → Bool) : Option α :=
|
||
if h : 0 < as.size then
|
||
let a0 := as[0]
|
||
some <| as.foldl (init := a0) (start := 1) fun best a =>
|
||
if lt best a then a else best
|
||
else
|
||
none
|
||
|
||
@[inline]
|
||
def partition (p : α → Bool) (as : Array α) : Array α × Array α := Id.run do
|
||
let mut bs := #[]
|
||
let mut cs := #[]
|
||
for a in as do
|
||
if p a then
|
||
bs := bs.push a
|
||
else
|
||
cs := cs.push a
|
||
return (bs, cs)
|
||
|
||
def reverse (as : Array α) : Array α :=
|
||
if h : as.size ≤ 1 then
|
||
as
|
||
else
|
||
loop as 0 ⟨as.size - 1, Nat.pred_lt (mt (fun h : as.size = 0 => h ▸ by decide) h)⟩
|
||
where
|
||
termination {i j : Nat} (h : i < j) : j - 1 - (i + 1) < j - i := by
|
||
rw [Nat.sub_sub, Nat.add_comm]
|
||
exact Nat.lt_of_le_of_lt (Nat.pred_le _) (Nat.sub_succ_lt_self _ _ h)
|
||
loop (as : Array α) (i : Nat) (j : Fin as.size) :=
|
||
if h : i < j then
|
||
have := termination h
|
||
let as := as.swap i j (Nat.lt_trans h j.2)
|
||
have : j-1 < as.size := by rw [size_swap]; exact Nat.lt_of_le_of_lt (Nat.pred_le _) j.2
|
||
loop as (i+1) ⟨j-1, this⟩
|
||
else
|
||
as
|
||
|
||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
def popWhile (p : α → Bool) (as : Array α) : Array α :=
|
||
if h : as.size > 0 then
|
||
if p (as[as.size - 1]'(Nat.sub_lt h (by decide))) then
|
||
popWhile p as.pop
|
||
else
|
||
as
|
||
else
|
||
as
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
|
||
def takeWhile (p : α → Bool) (as : Array α) : Array α :=
|
||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
go (i : Nat) (r : Array α) : Array α :=
|
||
if h : i < as.size then
|
||
let a := as[i]
|
||
if p a then
|
||
go (i+1) (r.push a)
|
||
else
|
||
r
|
||
else
|
||
r
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
go 0 #[]
|
||
|
||
/--
|
||
Remove the element at a given index from an array without a runtime bounds checks,
|
||
using a `Nat` index and a tactic-provided bound.
|
||
|
||
This function takes worst case O(n) time because
|
||
it has to backshift all elements at positions greater than `i`.-/
|
||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
def eraseIdx (a : Array α) (i : Nat) (h : i < a.size := by get_elem_tactic) : Array α :=
|
||
if h' : i + 1 < a.size then
|
||
let a' := a.swap (i + 1) i
|
||
a'.eraseIdx (i + 1) (by simp [a', h'])
|
||
else
|
||
a.pop
|
||
termination_by a.size - i
|
||
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ h
|
||
|
||
-- This is required in `Lean.Data.PersistentHashMap`.
|
||
@[simp] theorem size_eraseIdx (a : Array α) (i : Nat) (h) : (a.eraseIdx i h).size = a.size - 1 := by
|
||
induction a, i, h using Array.eraseIdx.induct with
|
||
| @case1 a i h h' a' ih =>
|
||
unfold eraseIdx
|
||
simp +zetaDelta [h', a', ih]
|
||
| case2 a i h h' =>
|
||
unfold eraseIdx
|
||
simp [h']
|
||
|
||
/-- Remove the element at a given index from an array, or do nothing if the index is out of bounds.
|
||
|
||
This function takes worst case O(n) time because
|
||
it has to backshift all elements at positions greater than `i`.-/
|
||
def eraseIdxIfInBounds (a : Array α) (i : Nat) : Array α :=
|
||
if h : i < a.size then a.eraseIdx i h else a
|
||
|
||
/-- Remove the element at a given index from an array, or panic if the index is out of bounds.
|
||
|
||
This function takes worst case O(n) time because
|
||
it has to backshift all elements at positions greater than `i`. -/
|
||
def eraseIdx! (a : Array α) (i : Nat) : Array α :=
|
||
if h : i < a.size then a.eraseIdx i h else panic! "invalid index"
|
||
|
||
def erase [BEq α] (as : Array α) (a : α) : Array α :=
|
||
match as.indexOf? a with
|
||
| none => as
|
||
| some i => as.eraseIdx i
|
||
|
||
/-- Erase the first element that satisfies the predicate `p`. -/
|
||
def eraseP (as : Array α) (p : α → Bool) : Array α :=
|
||
match as.findIdx? p with
|
||
| none => as
|
||
| some i => as.eraseIdxIfInBounds i
|
||
|
||
/-- Insert element `a` at position `i`. -/
|
||
@[inline] def insertIdx (as : Array α) (i : Nat) (a : α) (_ : i ≤ as.size := by get_elem_tactic) : Array α :=
|
||
let rec @[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
loop (as : Array α) (j : Fin as.size) :=
|
||
if i < j then
|
||
let j' : Fin as.size := ⟨j-1, Nat.lt_of_le_of_lt (Nat.pred_le _) j.2⟩
|
||
let as := as.swap j' j
|
||
loop as ⟨j', by rw [size_swap]; exact j'.2⟩
|
||
else
|
||
as
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
let j := as.size
|
||
let as := as.push a
|
||
loop as ⟨j, size_push .. ▸ j.lt_succ_self⟩
|
||
|
||
@[deprecated insertIdx (since := "2024-11-20")] abbrev insertAt := @insertIdx
|
||
|
||
/-- Insert element `a` at position `i`. Panics if `i` is not `i ≤ as.size`. -/
|
||
def insertIdx! (as : Array α) (i : Nat) (a : α) : Array α :=
|
||
if h : i ≤ as.size then
|
||
insertIdx as i a
|
||
else panic! "invalid index"
|
||
|
||
@[deprecated insertIdx! (since := "2024-11-20")] abbrev insertAt! := @insertIdx!
|
||
|
||
/-- Insert element `a` at position `i`, or do nothing if `as.size < i`. -/
|
||
def insertIdxIfInBounds (as : Array α) (i : Nat) (a : α) : Array α :=
|
||
if h : i ≤ as.size then
|
||
insertIdx as i a
|
||
else
|
||
as
|
||
|
||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : Nat) : Bool :=
|
||
if h : i < as.size then
|
||
let a := as[i]
|
||
have : i < bs.size := Nat.lt_of_lt_of_le h hle
|
||
let b := bs[i]
|
||
if a == b then
|
||
isPrefixOfAux as bs hle (i+1)
|
||
else
|
||
false
|
||
else
|
||
true
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
|
||
/-- Return true iff `as` is a prefix of `bs`.
|
||
That is, `bs = as ++ t` for some `t : List α`.-/
|
||
def isPrefixOf [BEq α] (as bs : Array α) : Bool :=
|
||
if h : as.size ≤ bs.size then
|
||
isPrefixOfAux as bs h 0
|
||
else
|
||
false
|
||
|
||
@[semireducible, specialize] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
def zipWithAux (as : Array α) (bs : Array β) (f : α → β → γ) (i : Nat) (cs : Array γ) : Array γ :=
|
||
if h : i < as.size then
|
||
let a := as[i]
|
||
if h : i < bs.size then
|
||
let b := bs[i]
|
||
zipWithAux as bs f (i+1) <| cs.push <| f a b
|
||
else
|
||
cs
|
||
else
|
||
cs
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
|
||
@[inline] def zipWith (as : Array α) (bs : Array β) (f : α → β → γ) : Array γ :=
|
||
zipWithAux as bs f 0 #[]
|
||
|
||
def zip (as : Array α) (bs : Array β) : Array (α × β) :=
|
||
zipWith as bs Prod.mk
|
||
|
||
def zipWithAll (as : Array α) (bs : Array β) (f : Option α → Option β → γ) : Array γ :=
|
||
go as bs 0 #[]
|
||
where go (as : Array α) (bs : Array β) (i : Nat) (cs : Array γ) :=
|
||
if i < max as.size bs.size then
|
||
let a := as[i]?
|
||
let b := bs[i]?
|
||
go as bs (i+1) (cs.push (f a b))
|
||
else
|
||
cs
|
||
termination_by max as.size bs.size - i
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
|
||
def unzip (as : Array (α × β)) : Array α × Array β :=
|
||
as.foldl (init := (#[], #[])) fun (as, bs) (a, b) => (as.push a, bs.push b)
|
||
|
||
@[deprecated partition (since := "2024-11-06")]
|
||
def split (as : Array α) (p : α → Bool) : Array α × Array α :=
|
||
as.foldl (init := (#[], #[])) fun (as, bs) a =>
|
||
if p a then (as.push a, bs) else (as, bs.push a)
|
||
|
||
/-! ### Lexicographic ordering -/
|
||
|
||
instance instLT [LT α] : LT (Array α) := ⟨fun as bs => as.toList < bs.toList⟩
|
||
instance instLE [LT α] : LE (Array α) := ⟨fun as bs => as.toList ≤ bs.toList⟩
|
||
|
||
-- See `Init.Data.Array.Lex.Basic` for the boolean valued lexicographic comparator.
|
||
|
||
/-! ## Auxiliary functions used in metaprogramming.
|
||
|
||
We do not currently intend to provide verification theorems for these functions.
|
||
-/
|
||
|
||
/- ### reduceOption -/
|
||
|
||
/-- Drop `none`s from a Array, and replace each remaining `some a` with `a`. -/
|
||
@[inline] def reduceOption (as : Array (Option α)) : Array α :=
|
||
as.filterMap id
|
||
|
||
/-! ### eraseReps -/
|
||
|
||
/--
|
||
`O(|l|)`. Erase repeated adjacent elements. Keeps the first occurrence of each run.
|
||
* `eraseReps #[1, 3, 2, 2, 2, 3, 5] = #[1, 3, 2, 3, 5]`
|
||
-/
|
||
def eraseReps {α} [BEq α] (as : Array α) : Array α :=
|
||
if h : 0 < as.size then
|
||
let ⟨last, r⟩ := as.foldl (init := (as[0], #[])) fun ⟨last, r⟩ a =>
|
||
if a == last then ⟨last, r⟩ else ⟨a, r.push last⟩
|
||
r.push last
|
||
else
|
||
#[]
|
||
|
||
/-! ### allDiff -/
|
||
|
||
private def allDiffAuxAux [BEq α] (as : Array α) (a : α) : forall (i : Nat), i < as.size → Bool
|
||
| 0, _ => true
|
||
| i+1, h =>
|
||
have : i < as.size := Nat.lt_trans (Nat.lt_succ_self _) h;
|
||
a != as[i] && allDiffAuxAux as a i this
|
||
|
||
@[semireducible] -- This is otherwise irreducible because it uses well-founded recursion.
|
||
private def allDiffAux [BEq α] (as : Array α) (i : Nat) : Bool :=
|
||
if h : i < as.size then
|
||
allDiffAuxAux as as[i] i h && allDiffAux as (i+1)
|
||
else
|
||
true
|
||
decreasing_by simp_wf; decreasing_trivial_pre_omega
|
||
|
||
def allDiff [BEq α] (as : Array α) : Bool :=
|
||
allDiffAux as 0
|
||
|
||
/-! ### getEvenElems -/
|
||
|
||
@[inline] def getEvenElems (as : Array α) : Array α :=
|
||
(·.2) <| as.foldl (init := (true, Array.empty)) fun (even, r) a =>
|
||
if even then
|
||
(false, r.push a)
|
||
else
|
||
(true, r)
|
||
|
||
/-! ### Repr and ToString -/
|
||
|
||
instance {α : Type u} [Repr α] : Repr (Array α) where
|
||
reprPrec a _ :=
|
||
let _ : Std.ToFormat α := ⟨repr⟩
|
||
if a.size == 0 then
|
||
"#[]"
|
||
else
|
||
Std.Format.bracketFill "#[" (Std.Format.joinSep (toList a) ("," ++ Std.Format.line)) "]"
|
||
|
||
instance [ToString α] : ToString (Array α) where
|
||
toString a := "#" ++ toString a.toList
|
||
|
||
end Array
|
||
|
||
export Array (mkArray)
|