lean4-htt/src/Init/Grind/Injective.lean
Leonardo de Moura 4c9601e60f
feat: support for injective functions in grind (#10483)
This PR completes support for injective functions in grind. See
examples:
```lean

/-! Add some injectivity theorems. -/

def double (x : Nat) := 2*x

@[grind inj] theorem double_inj : Function.Injective double := by
  grind [Function.Injective, double]

structure InjFn (α : Type) (β : Type) where
  f : α → β
  h : Function.Injective f

instance : CoeFun (InjFn α β) (fun _ => α → β) where
  coe s := s.f

@[grind inj] theorem fn_inj (F : InjFn α β) : Function.Injective (F : α → β) := by
  grind [Function.Injective, cases InjFn]

def toList (a : α) : List α := [a]

@[grind inj] theorem toList_inj : Function.Injective (toList : α → List α) := by
  grind [Function.Injective, toList]

/-! Examples -/

example (x y : Nat) : toList (double x) = toList (double y) → x = y := by
  grind

example (f : InjFn (List Nat) α) (x y z : Nat)
    : f (toList (double x)) = f (toList y) →
      y = double z →
      x = z := by
  grind
```
2025-09-21 06:31:46 +00:00

41 lines
1.3 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
module
prelude
public import Init.Data.Function
public import Init.Classical
public section
namespace Lean.Grind
open Function
theorem _root_.Function.Injective.leftInverse
{α β} (f : α → β) (hf : Injective f) [hα : Nonempty α] :
∃ g : β → α, LeftInverse g f := by
classical
cases hα; next a0 =>
let g : β → α := fun b =>
if h : ∃ a, f a = b then Classical.choose h else a0
exists g
intro a
have h : ∃ a', f a' = f a := ⟨a, rfl⟩
have hfa : f (Classical.choose h) = f a := Classical.choose_spec h
have : Classical.choose h = a := hf hfa
simp [g, h, this]
noncomputable def leftInv {α : Sort u} {β : Sort v} (f : α → β) (hf : Injective f) [Nonempty α] : β → α :=
Classical.choose (hf.leftInverse f)
theorem leftInv_eq {α : Sort u} {β : Sort v} (f : α → β) (hf : Injective f) [Nonempty α] (a : α) : leftInv f hf (f a) = a :=
Classical.choose_spec (hf.leftInverse f) a
@[app_unexpander leftInv]
meta def leftInvUnexpander : PrettyPrinter.Unexpander := fun stx => do
match stx with
| `($_ $f:term $_) => `($f⁻¹)
| `($_ $f:term $_ $a:term) => `($f⁻¹ $a)
| _ => throw ()
end Lean.Grind