Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Batteries/Data/Fin/Basic.lean
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ The function `p` is not evaluated on further inputs after the first `i` is found
@[inline] def find? (p : Fin n → Bool) : Option (Fin n) :=
findSome? <| Option.guard fun i => p i

/--
Returns true if `p i` is true for some `i`.

Short-circuits upon encountering the first true.
-/
protected abbrev any (p : Fin n → Bool) := find? p |>.isSome

/--
Returns true if `p i` is true for every `i`.

Short-circuits upon encountering the first false.
-/
protected abbrev all (p : Fin n → Bool) := find? (! p ·) |>.isNone
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also consider simply ! any (! p ·).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potatoes/Tomatoes? I don't have a preference either way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer using all.


/-- Compute `i / n`, where `n` is a `Nat` and inferred the type of `i`. -/
def divNat (i : Fin (m * n)) : Fin m :=
⟨i / n, Nat.div_lt_of_lt_mul <| Nat.mul_comm m n ▸ i.is_lt⟩
Expand Down
28 changes: 28 additions & 0 deletions Batteries/Data/Fin/Lemmas.lean
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ theorem find?_succ {p : Fin (n+1) → Bool} :
theorem find?_eq_some_iff {p : Fin n → Bool} :
find? p = some i ↔ p i ∧ ∀ j, j < i → p j = false := by simp [find?, and_assoc]

@[simp]
theorem isSome_find?_iff {p : Fin n → Bool} :
(find? p).isSome ↔ ∃ i, p i := by simp [find?]

Expand Down Expand Up @@ -203,6 +204,33 @@ theorem exists_iff_exists_minimal (p : Fin n → Prop) [DecidablePred p] :
simpa only [decide_eq_true_iff, decide_eq_false_iff_not] using
exists_eq_true_iff_exists_minimal_eq_true (p ·)

/-! ### any/all -/

theorem any_eq_true_iff {p : Fin n → Bool} : Fin.any p = true ↔ ∃ i, p i = true := by simp

theorem any_eq_false_iff {p : Fin n → Bool} : Fin.any p = false ↔ ∀ i, p i = false := by simp

theorem any_eq_any_finRange {p : Fin n → Bool} : Fin.any p = (List.finRange n).any p := by
rw [Bool.eq_iff_iff]
simp only [Fin.any, find?_eq_find?_finRange, List.find?_isSome, List.any_eq, decide_eq_true_eq]

theorem all_eq_true_iff {p : Fin n → Bool} : Fin.all p = true ↔ ∀ i, p i = true := by simp

theorem all_eq_false_iff {p : Fin n → Bool} : Fin.all p = false ↔ ∃ i, p i = false := by simp

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So arguably we are missing some lemmas but you could argue they are covered by the fact this is just an abbrev.

I would expect any_zero, all_zero, any_succ and all_succ, though.

I also think you want something like not_any_eq_all_not and not_all_eq_any_not which are not hard proofs but I think are probably worth having. You could also have all_eq_not_any_not in the same way. In general I would consider what lemmas from here: https://leanprover-community.github.io/mathlib4_docs/Init/Data/List/Lemmas.html#List.not_any_eq_all_not are wanted by analogy.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about going a step further and have classes to standardize the basic API for all and any?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is an interesting idea. Arguably could do the same for things like findSome?...

theorem all_eq_all_finRange {p : Fin n → Bool} : Fin.all p = (List.finRange n).all p := by
rw [Bool.eq_iff_iff]
simp only [Fin.all, find?_eq_find?_finRange, Option.isNone_iff_eq_none, List.find?_eq_none,
Bool.not_eq_eq_eq_not, Bool.not_true, Bool.not_eq_false, List.all_eq, decide_eq_true_eq]

-- The instance in Lean is not tail recursive and leads to stack overflow.
instance (p : Fin n → Prop) [DecidablePred p] : Decidable (∃ i, p i) :=
decidable_of_iff (Fin.any (p ·) = true) (by simp)

-- The instance in Lean is not tail recursive and leads to stack overflow.
instance (p : Fin n → Prop) [DecidablePred p] : Decidable (∀ i, p i) :=
decidable_of_iff (Fin.all (p ·) = true) (by simp)
Comment on lines +226 to +232
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't these form instance diamonds with instances in mathlib?


/-! ### divNat / modNat / mkDivMod -/

@[simp] theorem coe_divNat (i : Fin (m * n)) : (i.divNat : Nat) = i / n := rfl
Expand Down