mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-31 01:04:07 +00:00
Compare commits
1 Commits
paul/fix-h
...
simpCongrI
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e40623e3e |
@@ -5,10 +5,13 @@ Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.AddDecl
|
||||
import Lean.Class
|
||||
import Lean.ReservedNameAction
|
||||
import Lean.ResolveName
|
||||
import Lean.Meta.AppBuilder
|
||||
import Lean.Class
|
||||
import Lean.Meta.Tactic.Subst
|
||||
import Lean.Meta.Tactic.Intro
|
||||
import Lean.Meta.Tactic.Assert
|
||||
|
||||
namespace Lean.Meta
|
||||
|
||||
@@ -133,32 +136,6 @@ private def fixKindsForDependencies (info : FunInfo) (kinds : Array CongrArgKind
|
||||
break
|
||||
return kinds
|
||||
|
||||
/--
|
||||
(Tries to) cast expression `e` to the given type using the equations `eqs`.
|
||||
`deps` contains the indices of the relevant equalities.
|
||||
Remark: deps is sorted.
|
||||
-/
|
||||
private partial def mkCast (e : Expr) (type : Expr) (deps : Array Nat) (eqs : Array (Option Expr)) : MetaM Expr := do
|
||||
let rec go (i : Nat) (type : Expr) : MetaM Expr := do
|
||||
if i < deps.size then
|
||||
match eqs[deps[i]!]! with
|
||||
| none => go (i+1) type
|
||||
| some major =>
|
||||
let some (_, lhs, rhs) := (← inferType major).eq? | unreachable!
|
||||
if (← pure major.isFVar <&&> dependsOn type major.fvarId!) then
|
||||
let motive ← mkLambdaFVars #[rhs, major] type
|
||||
let typeNew := type.replaceFVar rhs lhs |>.replaceFVar major (← mkEqRefl lhs)
|
||||
let minor ← go (i+1) typeNew
|
||||
mkEqRec motive minor major
|
||||
else
|
||||
let motive ← mkLambdaFVars #[rhs] type
|
||||
let typeNew := type.replaceFVar rhs lhs
|
||||
let minor ← go (i+1) typeNew
|
||||
mkEqNDRec motive minor major
|
||||
else
|
||||
return e
|
||||
go 0 type
|
||||
|
||||
/-- Returns `true` if `kinds` contains `.cast` or `.subsingletonInst` -/
|
||||
private def hasCastLike (kinds : Array CongrArgKind) : Bool :=
|
||||
kinds.any fun kind => kind matches .cast | .subsingletonInst
|
||||
@@ -260,6 +237,63 @@ def getCongrSimpKindsForArgZero (info : FunInfo) : MetaM (Array CongrArgKind) :=
|
||||
result := result.push .fixed
|
||||
return fixKindsForDependencies info result
|
||||
|
||||
/--
|
||||
Auxiliary type for applying `mkCast` at `mkCongrSimpCore?`
|
||||
-/
|
||||
private inductive EqInfo where
|
||||
| /-- `fvarId` is an equality for "type casting." -/
|
||||
hyp (fvarId : FVarId)
|
||||
| /--
|
||||
`lhs` and `rhs` are `Decidable` instances which should have the same type after
|
||||
we have applied other type casting operations. We use the helper theorem `Decidable.eq`
|
||||
to perform the type cast operation.
|
||||
-/
|
||||
decSubsingleton (lhs rhs : FVarId)
|
||||
|
||||
/--
|
||||
Helper function for applying the substitution `s`.
|
||||
It assumes that all entries in `s` map free variables to free variables.
|
||||
-/
|
||||
private def getFVarId (s : FVarSubst) (fvarId : FVarId) : FVarId :=
|
||||
if let some h := s.find? fvarId then h.fvarId! else fvarId
|
||||
|
||||
/--
|
||||
(Tries to) cast free variable `fvarId` to the given type using the equations `eqs`.
|
||||
`deps` contains the indices of the relevant equalities.
|
||||
Remark: deps is sorted.
|
||||
-/
|
||||
private partial def mkCast (fvarId : FVarId) (type : Expr) (deps : Array Nat) (eqs : Array (Option EqInfo)) : MetaM Expr := do
|
||||
-- Remark: we use the `subst` tactic to avoid re-implementing the `revert`/`intro` logic used there.
|
||||
let eqs := deps.filterMap fun idx => eqs[idx]!
|
||||
if eqs.isEmpty then return mkFVar fvarId
|
||||
let mvar ← mkFreshExprMVar type
|
||||
let mut mvarId := mvar.mvarId!
|
||||
let mut s : FVarSubst := {}
|
||||
for eq in eqs do
|
||||
match eq with
|
||||
| .hyp fvarId =>
|
||||
let fvarId := getFVarId s fvarId
|
||||
let (s', mvarId') ← substCore mvarId fvarId (symm := true) s
|
||||
s := s'
|
||||
mvarId := mvarId'
|
||||
| .decSubsingleton lhsFVarId rhsFVarId =>
|
||||
let lhsFVarId := getFVarId s lhsFVarId
|
||||
let rhsFVarId := getFVarId s rhsFVarId
|
||||
let lhs := mkFVar lhsFVarId
|
||||
let rhs := mkFVar rhsFVarId
|
||||
let eq ← mvarId.withContext <| mkEq lhs rhs
|
||||
let h ← mvarId.withContext <| mkAppM ``Subsingleton.elim #[lhs, rhs]
|
||||
mvarId ← mvarId.assert `h eq h
|
||||
let (fvarId', mvarId') ← mvarId.intro1
|
||||
let (s', mvarId') ← substCore mvarId' fvarId' (symm := true) s
|
||||
s := s'
|
||||
mvarId := mvarId'
|
||||
let fvarId := getFVarId s fvarId
|
||||
mvarId.assign (mkFVar fvarId)
|
||||
let r ← instantiateMVars mvar
|
||||
trace[Meta.debug] "{r} : {← inferType r}"
|
||||
return r
|
||||
|
||||
/--
|
||||
Creates a congruence theorem that is useful for the simplifier and `congr` tactic.
|
||||
-/
|
||||
@@ -277,7 +311,7 @@ where
|
||||
Create a congruence theorem that is useful for the simplifier.
|
||||
In this kind of theorem, if the i-th argument is a `cast` argument, then the theorem
|
||||
contains an input `a_i` representing the i-th argument in the left-hand-side, and
|
||||
it appears with a cast (e.g., `Eq.drec ... a_i ...`) in the right-hand-side.
|
||||
it appears with a cast (e.g., `Eq.rec ... a_i ...`) in the right-hand-side.
|
||||
The idea is that the right-hand-side of this theorem "tells" the simplifier
|
||||
how the resulting term looks like. -/
|
||||
mk? (f : Expr) (info : FunInfo) (kinds : Array CongrArgKind) : MetaM (Option CongrTheorem) := do
|
||||
@@ -285,7 +319,7 @@ where
|
||||
let fType ← inferType f
|
||||
forallBoundedTelescope fType kinds.size (cleanupAnnotations := true) fun lhss _ => do
|
||||
if lhss.size != kinds.size then return none
|
||||
let rec go (i : Nat) (rhss : Array Expr) (eqs : Array (Option Expr)) (hyps : Array Expr) : MetaM CongrTheorem := do
|
||||
let rec go (i : Nat) (rhss : Array Expr) (eqs : Array (Option EqInfo)) (hyps : Array Expr) : MetaM CongrTheorem := do
|
||||
if i == kinds.size then
|
||||
let lhs := mkAppN f lhss
|
||||
let rhs := mkAppN f rhss
|
||||
@@ -300,11 +334,11 @@ where
|
||||
let localDecl ← lhss[i]!.fvarId!.getDecl
|
||||
withLocalDecl localDecl.userName localDecl.binderInfo localDecl.type fun rhs => do
|
||||
withLocalDeclD (localDecl.userName.appendBefore "e_") (← mkEq lhss[i]! rhs) fun eq => do
|
||||
go (i+1) (rhss.push rhs) (eqs.push eq) (hyps.push rhs |>.push eq)
|
||||
go (i+1) (rhss.push rhs) (eqs.push <| some <| .hyp eq.fvarId!) (hyps.push rhs |>.push eq)
|
||||
| .fixed => go (i+1) (rhss.push lhss[i]!) (eqs.push none) hyps
|
||||
| .cast =>
|
||||
let rhsType := (← inferType lhss[i]!).replaceFVars (lhss[*...rhss.size]) rhss
|
||||
let rhs ← mkCast lhss[i]! rhsType info.paramInfo[i]!.backDeps eqs
|
||||
let rhs ← mkCast lhss[i]!.fvarId! rhsType info.paramInfo[i]!.backDeps eqs
|
||||
go (i+1) (rhss.push rhs) (eqs.push none) hyps
|
||||
| .subsingletonInst =>
|
||||
-- The `lhs` does not need to instance implicit since it can be inferred from the LHS
|
||||
@@ -314,9 +348,7 @@ where
|
||||
let rhsType := lhsType.replaceFVars (lhss[*...rhss.size]) rhss
|
||||
let rhsBi := if subsingletonInstImplicitRhs then .instImplicit else .implicit
|
||||
withLocalDecl (← lhss[i]!.fvarId!.getDecl).userName rhsBi rhsType fun rhs => do
|
||||
let lhs' ← mkCast lhs rhsType info.paramInfo[i]!.backDeps eqs
|
||||
let heq ← mkAppM ``Subsingleton.elim #[lhs', rhs]
|
||||
go (i+1) (rhss.push rhs) (eqs.push heq) (hyps.push rhs)
|
||||
go (i+1) (rhss.push rhs) (eqs.push <| some <| .decSubsingleton lhs.fvarId! rhs.fvarId!) (hyps.push rhs)
|
||||
return some (← go 0 #[] #[] #[])
|
||||
catch _ =>
|
||||
return none
|
||||
|
||||
@@ -59,3 +59,15 @@ info: test7.congr_simp.{u} {α : Type u} {i : DecidableEq α} [i✝ : DecidableE
|
||||
-/
|
||||
#guard_msgs in
|
||||
#check test7.congr_simp
|
||||
|
||||
def test8 (p : Prop) [Decidable p] (_ : decide p = true) : Nat := 3
|
||||
|
||||
/--
|
||||
info: test8.congr_simp (p p✝ : Prop) (e_p : p = p✝) {inst✝ : Decidable p} [Decidable p✝] (x✝ : decide p = true) :
|
||||
test8 p x✝ =
|
||||
test8 p✝
|
||||
(Eq.ndrec (motive := fun p => ∀ [inst : Decidable p], decide p = true)
|
||||
(fun [inst : Decidable p] => Subsingleton.elim inst✝ inst ▸ x✝) e_p)
|
||||
-/
|
||||
#guard_msgs in
|
||||
#check test8.congr_simp
|
||||
|
||||
757
tests/lean/run/congrSimpMathlibIssue.lean
Normal file
757
tests/lean/run/congrSimpMathlibIssue.lean
Normal file
@@ -0,0 +1,757 @@
|
||||
import Lean.Elab.Term
|
||||
|
||||
/-!
|
||||
# Turán's theorem
|
||||
-/
|
||||
|
||||
set_option warn.sorry false
|
||||
|
||||
section Mathlib.Tactic.TypeStar
|
||||
|
||||
open Lean
|
||||
|
||||
elab "Sort*" : term => do
|
||||
let u ← Lean.Meta.mkFreshLevelMVar
|
||||
Elab.Term.levelMVarToParam (.sort u)
|
||||
|
||||
elab "Type*" : term => do
|
||||
let u ← Lean.Meta.mkFreshLevelMVar
|
||||
Elab.Term.levelMVarToParam (.sort (.succ u))
|
||||
|
||||
end Mathlib.Tactic.TypeStar
|
||||
|
||||
section Mathlib.Data.Set.Defs
|
||||
|
||||
universe u
|
||||
variable {α : Type u}
|
||||
|
||||
/-- A set is a collection of elements of some type `α`.
|
||||
|
||||
Although `Set` is defined as `α → Prop`, this is an implementation detail which should not be
|
||||
relied on. Instead, `setOf` and membership of a set (`∈`) should be used to convert between sets
|
||||
and predicates.
|
||||
-/
|
||||
def Set (α : Type u) := α → Prop
|
||||
|
||||
/-- Turn a predicate `p : α → Prop` into a set, also written as `{x | p x}` -/
|
||||
def setOf {α : Type u} (p : α → Prop) : Set α :=
|
||||
p
|
||||
|
||||
namespace Set
|
||||
|
||||
/-- Membership in a set -/
|
||||
protected def Mem (s : Set α) (a : α) : Prop :=
|
||||
s a
|
||||
|
||||
instance : Membership α (Set α) :=
|
||||
⟨Set.Mem⟩
|
||||
|
||||
end Set
|
||||
|
||||
end Mathlib.Data.Set.Defs
|
||||
|
||||
section Mathlib.Order.Defs.Unbundled
|
||||
|
||||
variable {α : Sort*} (r : α → α → Prop)
|
||||
|
||||
/-- `IsSymm` as a definition, suitable for use in proofs. -/
|
||||
def Symmetric := ∀ ⦃x y⦄, r x y → r y x
|
||||
|
||||
end Mathlib.Order.Defs.Unbundled
|
||||
|
||||
section Mathlib.Data.List.Defs
|
||||
|
||||
namespace List
|
||||
|
||||
variable {α : Type*}
|
||||
|
||||
section Choose
|
||||
|
||||
variable (p : α → Prop) [DecidablePred p] (l : List α)
|
||||
|
||||
/-- Given a decidable predicate `p` and a proof of existence of `a ∈ l` such that `p a`,
|
||||
choose the first element with this property. This version returns both `a` and proofs
|
||||
of `a ∈ l` and `p a`. -/
|
||||
def chooseX : ∀ l : List α, ∀ _ : ∃ a, a ∈ l ∧ p a, { a // a ∈ l ∧ p a }
|
||||
| [], hp => False.elim (Exists.elim hp fun _ h => not_mem_nil h.left)
|
||||
| l :: ls, hp =>
|
||||
if pl : p l then ⟨l, ⟨mem_cons.mpr <| Or.inl rfl, pl⟩⟩
|
||||
else
|
||||
-- pattern matching on `hx` too makes this not reducible!
|
||||
let ⟨a, ha⟩ :=
|
||||
chooseX ls
|
||||
(hp.imp fun _ ⟨o, h₂⟩ => ⟨(mem_cons.mp o).resolve_left fun e => pl <| e ▸ h₂, h₂⟩)
|
||||
⟨a, mem_cons.mpr <| Or.inr ha.1, ha.2⟩
|
||||
|
||||
end Choose
|
||||
|
||||
end List
|
||||
|
||||
end Mathlib.Data.List.Defs
|
||||
|
||||
section Mathlib.Data.Set.CoeSort
|
||||
|
||||
namespace Set
|
||||
|
||||
universe u v w
|
||||
|
||||
variable {α : Type u} {β : Type v} {γ : Type w}
|
||||
|
||||
/-- Given the set `s`, `Elem s` is the `Type` of element of `s`.
|
||||
|
||||
It is currently an abbreviation so that instance coming from `Subtype` are available.
|
||||
If you're interested in making it a `def`, as it probably should be,
|
||||
you'll then need to create additional instances (and possibly prove lemmas about them).
|
||||
See e.g. `Mathlib/Data/Set/Order.lean`.
|
||||
-/
|
||||
@[coe, reducible] def Elem (s : Set α) : Type u := {x // x ∈ s}
|
||||
|
||||
/-- Coercion from a set to the corresponding subtype. -/
|
||||
instance : CoeSort (Set α) (Type u) := ⟨Elem⟩
|
||||
|
||||
end Set
|
||||
|
||||
end Mathlib.Data.Set.CoeSort
|
||||
|
||||
section Mathlib.Data.Multiset.Defs
|
||||
|
||||
universe v
|
||||
|
||||
open List Subtype Nat Function
|
||||
|
||||
variable {α : Type*} {β : Type v} {γ : Type*}
|
||||
|
||||
/-- `Multiset α` is the quotient of `List α` by list permutation. The result
|
||||
is a type of finite sets with duplicates allowed. -/
|
||||
def Multiset.{u} (α : Type u) : Type u :=
|
||||
Quotient (List.isSetoid α)
|
||||
|
||||
namespace Multiset
|
||||
|
||||
/-- The quotient map from `List α` to `Multiset α`. -/
|
||||
def ofList : List α → Multiset α :=
|
||||
Quot.mk _
|
||||
|
||||
section Mem
|
||||
|
||||
/-- `a ∈ s` means that `a` has nonzero multiplicity in `s`. -/
|
||||
def Mem (s : Multiset α) (a : α) : Prop :=
|
||||
Quot.liftOn s (fun l => a ∈ l) fun l₁ l₂ (e : l₁ ~ l₂) => propext <| e.mem_iff
|
||||
|
||||
instance : Membership α (Multiset α) :=
|
||||
⟨Mem⟩
|
||||
|
||||
instance decidableMem [DecidableEq α] (a : α) (s : Multiset α) : Decidable (a ∈ s) :=
|
||||
Quot.recOnSubsingleton s fun l ↦ inferInstanceAs (Decidable (a ∈ l))
|
||||
|
||||
end Mem
|
||||
|
||||
/-- The cardinality of a multiset is the sum of the multiplicities
|
||||
of all its elements, or simply the length of the underlying list. -/
|
||||
def card : Multiset α → Nat := Quot.lift length sorry
|
||||
|
||||
/-- Lift of the list `pmap` operation. Map a partial function `f` over a multiset
|
||||
`s` whose elements are all in the domain of `f`. -/
|
||||
nonrec def pmap {p : α → Prop} (f : ∀ a, p a → β) (s : Multiset α) : (∀ a ∈ s, p a) → Multiset β :=
|
||||
Quot.recOn s (fun l H => ofList (pmap f l H)) sorry
|
||||
|
||||
end Multiset
|
||||
|
||||
end Mathlib.Data.Multiset.Defs
|
||||
|
||||
section Mathlib.Data.Multiset.ZeroCons
|
||||
|
||||
universe v
|
||||
|
||||
open List Subtype Nat Function
|
||||
|
||||
variable {α : Type*} {β : Type v} {γ : Type*}
|
||||
|
||||
namespace Multiset
|
||||
|
||||
/-- `0 : Multiset α` is the empty set -/
|
||||
protected def zero : Multiset α :=
|
||||
ofList (@nil α)
|
||||
|
||||
instance : Zero (Multiset α) :=
|
||||
⟨Multiset.zero⟩
|
||||
|
||||
end Multiset
|
||||
|
||||
end Mathlib.Data.Multiset.ZeroCons
|
||||
|
||||
section Mathlib.Data.Multiset.Basic
|
||||
|
||||
universe v
|
||||
|
||||
open List Subtype Nat Function
|
||||
|
||||
variable {α : Type*} {β : Type v} {γ : Type*}
|
||||
|
||||
namespace Multiset
|
||||
|
||||
section Choose
|
||||
|
||||
variable (p : α → Prop) [DecidablePred p] (l : Multiset α)
|
||||
|
||||
/-- Given a proof `hp` that there exists a unique `a ∈ l` such that `p a`, `chooseX p l hp` returns
|
||||
that `a` together with proofs of `a ∈ l` and `p a`. -/
|
||||
def chooseX : ∀ _hp : ∃ a, a ∈ l ∧ p a, { a // a ∈ l ∧ p a } :=
|
||||
Quotient.recOn l (fun l' h => List.chooseX p l' h) sorry
|
||||
|
||||
end Choose
|
||||
|
||||
end Multiset
|
||||
|
||||
end Mathlib.Data.Multiset.Basic
|
||||
|
||||
section Mathlib.Data.Multiset.MapFold
|
||||
|
||||
variable {α β : Type*}
|
||||
|
||||
namespace Multiset
|
||||
|
||||
/-- `map f s` is the lift of the list `map` operation. The multiplicity
|
||||
of `b` in `map f s` is the number of `a ∈ s` (counting multiplicity)
|
||||
such that `f a = b`. -/
|
||||
def map (f : α → β) (s : Multiset α) : Multiset β :=
|
||||
Quot.liftOn s (fun l : List α => ofList <| l.map f) sorry
|
||||
|
||||
end Multiset
|
||||
|
||||
end Mathlib.Data.Multiset.MapFold
|
||||
|
||||
section Mathlib.Data.Multiset.Filter
|
||||
|
||||
variable {α : Type*}
|
||||
|
||||
namespace Multiset
|
||||
|
||||
variable (p : α → Prop) [DecidablePred p]
|
||||
|
||||
/-- `Filter p s` returns the elements in `s` (with the same multiplicities)
|
||||
which satisfy `p`, and removes the rest. -/
|
||||
def filter (s : Multiset α) : Multiset α :=
|
||||
Quot.liftOn s (fun l => ofList <| List.filter p l) sorry
|
||||
|
||||
end Multiset
|
||||
|
||||
end Mathlib.Data.Multiset.Filter
|
||||
|
||||
section Mathlib.Data.Finset.Defs
|
||||
|
||||
universe u
|
||||
|
||||
variable {α : Type*} {β : Type*} {γ : Type*}
|
||||
|
||||
/-- `Finset α` is the type of finite sets of elements of `α`. It is implemented
|
||||
as a multiset (a list up to permutation) which has no duplicate elements. -/
|
||||
structure Finset (α : Type*) where
|
||||
/-- The underlying multiset -/
|
||||
val : Multiset α
|
||||
|
||||
namespace Finset
|
||||
|
||||
theorem val_inj {s t : Finset α} : s.1 = t.1 ↔ s = t := sorry
|
||||
|
||||
instance : Membership α (Finset α) :=
|
||||
⟨fun s a => a ∈ s.1⟩
|
||||
|
||||
instance decidableMem [_h : DecidableEq α] (a : α) (s : Finset α) : Decidable (a ∈ s) :=
|
||||
Multiset.decidableMem _ _
|
||||
|
||||
end Finset
|
||||
|
||||
end Mathlib.Data.Finset.Defs
|
||||
|
||||
section Mathlib.Data.Finset.Dedup
|
||||
|
||||
universe u
|
||||
|
||||
variable {α : Type*} {β : Type*} {γ : Type*}
|
||||
|
||||
namespace Finset
|
||||
|
||||
end Finset
|
||||
|
||||
/-! ### dedup on list and multiset -/
|
||||
|
||||
namespace Multiset
|
||||
|
||||
variable [DecidableEq α] {s t : Multiset α}
|
||||
|
||||
/-- `toFinset s` removes duplicates from the multiset `s` to produce a finset. -/
|
||||
def toFinset (s : Multiset α) : Finset α := ⟨s⟩
|
||||
|
||||
end Multiset
|
||||
|
||||
end Mathlib.Data.Finset.Dedup
|
||||
|
||||
section Mathlib.Data.Finset.Empty
|
||||
|
||||
universe u
|
||||
|
||||
variable {α : Type*} {β : Type*} {γ : Type*}
|
||||
|
||||
namespace Finset
|
||||
|
||||
section Empty
|
||||
|
||||
variable {s : Finset α}
|
||||
|
||||
/-- The empty finset -/
|
||||
protected def empty : Finset α := ⟨0⟩
|
||||
|
||||
end Empty
|
||||
end Finset
|
||||
|
||||
end Mathlib.Data.Finset.Empty
|
||||
|
||||
section Mathlib.Data.Finset.Filter
|
||||
|
||||
variable {α : Type*}
|
||||
|
||||
namespace Finset
|
||||
|
||||
section Filter
|
||||
|
||||
variable (p : α → Prop) [DecidablePred p]
|
||||
|
||||
/-- `Finset.filter p s` is the set of elements of `s` that satisfy `p`.
|
||||
For example, one can use `s.filter (· ∈ t)` to get the intersection of `s` with `t : Set α`
|
||||
as a `Finset α` (when a `DecidablePred (· ∈ t)` instance is available). -/
|
||||
def filter (s : Finset α) : Finset α :=
|
||||
⟨s.1.filter p⟩
|
||||
|
||||
end Finset.Filter
|
||||
|
||||
end Mathlib.Data.Finset.Filter
|
||||
|
||||
section Mathlib.Data.Finset.Basic
|
||||
|
||||
variable {α : Type*}
|
||||
|
||||
namespace Finset
|
||||
|
||||
section Choose
|
||||
|
||||
variable (p : α → Prop) [DecidablePred p] (l : Finset α)
|
||||
|
||||
/-- Given a finset `l` and a predicate `p`, associate to a proof that there is a unique element of
|
||||
`l` satisfying `p` this unique element, as an element of the corresponding subtype. -/
|
||||
def chooseX (hp : ∃ a, a ∈ l ∧ p a) : { a // a ∈ l ∧ p a } :=
|
||||
Multiset.chooseX p l.val hp
|
||||
|
||||
/-- Given a finset `l` and a predicate `p`, associate to a proof that there is a unique element of
|
||||
`l` satisfying `p` this unique element, as an element of the ambient type. -/
|
||||
def choose (hp : ∃ a, a ∈ l ∧ p a) : α :=
|
||||
chooseX p l hp
|
||||
|
||||
end Choose
|
||||
|
||||
end Finset
|
||||
|
||||
end Mathlib.Data.Finset.Basic
|
||||
|
||||
section Mathlib.Data.Finset.Image
|
||||
|
||||
variable {α β γ : Type*}
|
||||
|
||||
namespace Finset
|
||||
|
||||
section Map
|
||||
|
||||
/-- When `f` is an embedding of `α` in `β` and `s` is a finset in `α`, then `s.map f` is the image
|
||||
finset in `β`. The embedding condition guarantees that there are no duplicates in the image. -/
|
||||
def map (f : α → β) (s : Finset α) : Finset β := ⟨s.1.map f⟩
|
||||
|
||||
end Map
|
||||
|
||||
section Image
|
||||
|
||||
variable [DecidableEq β]
|
||||
|
||||
/-- `image f s` is the forward image of `s` under `f`. -/
|
||||
def image (f : α → β) (s : Finset α) : Finset β :=
|
||||
(s.1.map f).toFinset
|
||||
|
||||
end Image
|
||||
|
||||
end Finset
|
||||
|
||||
end Mathlib.Data.Finset.Image
|
||||
|
||||
section Mathlib.Data.Finset.Card
|
||||
|
||||
variable {α β R : Type*}
|
||||
|
||||
namespace Finset
|
||||
|
||||
variable {s t : Finset α} {a b : α}
|
||||
|
||||
/-- `s.card` is the number of elements of `s`, aka its cardinality.
|
||||
The notation `#s` can be accessed in the `Finset` locale. -/
|
||||
def card (s : Finset α) : Nat :=
|
||||
Multiset.card s.1
|
||||
|
||||
end Finset
|
||||
|
||||
end Mathlib.Data.Finset.Card
|
||||
|
||||
section Mathlib.Data.Fintype.Defs
|
||||
|
||||
variable {α β γ : Type*}
|
||||
|
||||
/-- `Fintype α` means that `α` is finite, i.e. there are only
|
||||
finitely many distinct elements of type `α`. The evidence of this
|
||||
is a finset `elems` (a list up to permutation without duplicates),
|
||||
together with a proof that everything of type `α` is in the list. -/
|
||||
class Fintype (α : Type*) where
|
||||
/-- The `Finset` containing all elements of a `Fintype` -/
|
||||
elems : Finset α
|
||||
|
||||
namespace Finset
|
||||
|
||||
variable [Fintype α] {s t : Finset α}
|
||||
|
||||
/-- `univ` is the universal finite set of type `Finset α` implied from
|
||||
the assumption `Fintype α`. -/
|
||||
def univ : Finset α := @Fintype.elems α _
|
||||
|
||||
end Finset
|
||||
|
||||
namespace Fintype
|
||||
|
||||
/-- Given a predicate that can be represented by a finset, the subtype
|
||||
associated to the predicate is a fintype. -/
|
||||
protected def subtype {p : α → Prop} (s : Finset α) (H : ∀ x : α, x ∈ s ↔ p x) :
|
||||
Fintype { x // p x } :=
|
||||
⟨⟨s.1.pmap Subtype.mk fun x => (H x).1⟩⟩
|
||||
|
||||
end Fintype
|
||||
|
||||
end Mathlib.Data.Fintype.Defs
|
||||
|
||||
section Mathlib.Data.Fintype.Sets
|
||||
|
||||
variable {α β γ : Type*}
|
||||
|
||||
open Finset
|
||||
|
||||
namespace Set
|
||||
|
||||
variable {s t : Set α}
|
||||
|
||||
/-- Construct a finset enumerating a set `s`, given a `Fintype` instance. -/
|
||||
def toFinset (s : Set α) [Fintype s] : Finset α :=
|
||||
(@Finset.univ s _).map <| Subtype.val
|
||||
|
||||
end Set
|
||||
|
||||
instance Subtype.fintype (p : α → Prop) [DecidablePred p] [Fintype α] : Fintype { x // p x } :=
|
||||
Fintype.subtype (univ.filter p) sorry
|
||||
|
||||
end Mathlib.Data.Fintype.Sets
|
||||
|
||||
section Mathlib.Data.Sym.Sym2
|
||||
|
||||
open Function
|
||||
|
||||
universe u
|
||||
|
||||
variable {α β γ : Type*}
|
||||
|
||||
namespace Sym2
|
||||
|
||||
/-- This is the relation capturing the notion of pairs equivalent up to permutations. -/
|
||||
inductive Rel (α : Type u) : α × α → α × α → Prop
|
||||
| refl (x y : α) : Rel _ (x, y) (x, y)
|
||||
| swap (x y : α) : Rel _ (x, y) (y, x)
|
||||
|
||||
end Sym2
|
||||
|
||||
/-- `Sym2 α` is the symmetric square of `α`, which, in other words, is the
|
||||
type of unordered pairs. -/
|
||||
abbrev Sym2 (α : Type u) := Quot (Sym2.Rel α)
|
||||
|
||||
/-- Constructor for `Sym2`. This is the quotient map `α × α → Sym2 α`. -/
|
||||
protected abbrev Sym2.mk {α : Type*} (p : α × α) : Sym2 α := Quot.mk (Sym2.Rel α) p
|
||||
|
||||
namespace Sym2
|
||||
|
||||
/-- The universal property of `Sym2`; symmetric functions of two arguments are equivalent to
|
||||
functions from `Sym2`. Note that when `β` is `Prop`, it can sometimes be more convenient to use
|
||||
`Sym2.fromRel` instead. -/
|
||||
def lift : { f : α → α → β // ∀ a₁ a₂, f a₁ a₂ = f a₂ a₁ } → (Sym2 α → β) :=
|
||||
fun f => Quot.lift (uncurry f) <| by sorry
|
||||
|
||||
section Relations
|
||||
|
||||
variable {r : α → α → Prop}
|
||||
|
||||
/-- Symmetric relations define a set on `Sym2 α` by taking all those pairs
|
||||
of elements that are related.
|
||||
-/
|
||||
def fromRel (sym : Symmetric r) : Set (Sym2 α) :=
|
||||
setOf (lift ⟨r, fun _ _ => propext ⟨(sym ·), (sym ·)⟩⟩)
|
||||
|
||||
instance fromRel.decidablePred (sym : Symmetric r) [h : DecidableRel r] :
|
||||
DecidablePred (· ∈ Sym2.fromRel sym) := fun z => z.recOnSubsingleton fun _ => h _ _
|
||||
|
||||
end Relations
|
||||
|
||||
end Sym2
|
||||
|
||||
end Mathlib.Data.Sym.Sym2
|
||||
|
||||
section Mathlib.Data.List.Sym
|
||||
|
||||
namespace List
|
||||
|
||||
variable {α β : Type*}
|
||||
|
||||
section Sym2
|
||||
|
||||
/-- `xs.sym2` is a list of all unordered pairs of elements from `xs`.
|
||||
If `xs` has no duplicates then neither does `xs.sym2`. -/
|
||||
protected def sym2 : List α → List (Sym2 α)
|
||||
| [] => []
|
||||
| x :: xs => (x :: xs).map (fun y => .mk (x, y)) ++ xs.sym2
|
||||
|
||||
end Sym2
|
||||
|
||||
end List
|
||||
|
||||
end Mathlib.Data.List.Sym
|
||||
|
||||
section Mathlib.Data.Multiset.Sym
|
||||
|
||||
namespace Multiset
|
||||
|
||||
variable {α β : Type*}
|
||||
|
||||
section Sym2
|
||||
|
||||
/-- `m.sym2` is the multiset of all unordered pairs of elements from `m`, with multiplicity.
|
||||
If `m` has no duplicates then neither does `m.sym2`. -/
|
||||
protected def sym2 (m : Multiset α) : Multiset (Sym2 α) :=
|
||||
m.liftOn (fun xs => ofList xs.sym2) fun _ _ h => sorry
|
||||
|
||||
end Sym2
|
||||
|
||||
end Multiset
|
||||
|
||||
end Mathlib.Data.Multiset.Sym
|
||||
|
||||
section Mathlib.Data.Finset.Sym
|
||||
|
||||
namespace Finset
|
||||
|
||||
variable {α β : Type*}
|
||||
|
||||
protected def sym2 (s : Finset α) : Finset (Sym2 α) := ⟨s.1.sym2⟩
|
||||
|
||||
section
|
||||
variable {s t : Finset α} {a b : α}
|
||||
|
||||
instance _root_.Sym2.instFintype [Fintype α] : Fintype (Sym2 α) where
|
||||
elems := Finset.univ.sym2
|
||||
|
||||
end
|
||||
|
||||
end Finset
|
||||
|
||||
end Mathlib.Data.Finset.Sym
|
||||
|
||||
section Mathlib.Combinatorics.SimpleGraph.Basic
|
||||
|
||||
open Function
|
||||
|
||||
universe u v w
|
||||
|
||||
/-- A simple graph is an irreflexive symmetric relation `Adj` on a vertex type `V`.
|
||||
The relation describes which pairs of vertices are adjacent.
|
||||
There is exactly one edge for every pair of adjacent vertices;
|
||||
see `SimpleGraph.edgeSet` for the corresponding edge set.
|
||||
-/
|
||||
structure SimpleGraph (V : Type u) where
|
||||
/-- The adjacency relation of a simple graph. -/
|
||||
Adj : V → V → Prop
|
||||
|
||||
namespace SimpleGraph
|
||||
|
||||
variable {ι : Sort*} {V : Type u} (G : SimpleGraph V) {a b c u v w : V} {e : Sym2 V}
|
||||
|
||||
section EdgeSet
|
||||
|
||||
variable {G₁ G₂ : SimpleGraph V}
|
||||
|
||||
/-- The edges of G consist of the unordered pairs of vertices related by
|
||||
`G.Adj`. This is the order embedding; for the edge set of a particular graph, see
|
||||
`SimpleGraph.edgeSet`.
|
||||
|
||||
The way `edgeSet` is defined is such that `mem_edgeSet` is proved by `Iff.rfl`.
|
||||
(That is, `s(v, w) ∈ G.edgeSet` is definitionally equal to `G.Adj v w`.)
|
||||
-/
|
||||
-- Porting note: We need a separate definition so that dot notation works.
|
||||
def edgeSetEmbedding (V : Type*) : SimpleGraph V → Set (Sym2 V) :=
|
||||
fun G => Sym2.fromRel (r := G.1) sorry
|
||||
|
||||
/-- `G.edgeSet` is the edge set for `G`.
|
||||
This is an abbreviation for `edgeSetEmbedding G` that permits dot notation. -/
|
||||
abbrev edgeSet (G : SimpleGraph V) : Set (Sym2 V) := edgeSetEmbedding V G
|
||||
|
||||
variable (G₁ G₂)
|
||||
|
||||
instance decidableMemEdgeSet [DecidableRel G.Adj] : DecidablePred (· ∈ G.edgeSet) :=
|
||||
Sym2.fromRel.decidablePred sorry
|
||||
|
||||
end EdgeSet
|
||||
|
||||
end SimpleGraph
|
||||
|
||||
end Mathlib.Combinatorics.SimpleGraph.Basic
|
||||
|
||||
section Mathlib.Combinatorics.SimpleGraph.Finite
|
||||
namespace SimpleGraph
|
||||
|
||||
variable {V : Type*} (G : SimpleGraph V) {e : Sym2 V}
|
||||
variable {G₁ G₂ : SimpleGraph V} [Fintype G.edgeSet] [Fintype G₁.edgeSet] [Fintype G₂.edgeSet]
|
||||
|
||||
/-- The `edgeSet` of the graph as a `Finset`. -/
|
||||
abbrev edgeFinset : Finset (Sym2 V) := Set.toFinset G.edgeSet
|
||||
|
||||
end SimpleGraph
|
||||
end Mathlib.Combinatorics.SimpleGraph.Finite
|
||||
|
||||
section Mathlib.Combinatorics.SimpleGraph.Clique
|
||||
|
||||
namespace SimpleGraph
|
||||
|
||||
variable {α β : Type*} (G H : SimpleGraph α)
|
||||
|
||||
/-! ### `n`-cliques -/
|
||||
|
||||
section NClique
|
||||
|
||||
variable {n : Nat} {s : Finset α}
|
||||
|
||||
/-- An `n`-clique in a graph is a set of `n` vertices which are pairwise connected. -/
|
||||
structure IsNClique (G : SimpleGraph α) (n : Nat) (s : Finset α) : Prop where
|
||||
|
||||
end NClique
|
||||
|
||||
/-! ### Graphs without cliques -/
|
||||
|
||||
|
||||
section CliqueFree
|
||||
|
||||
variable {m n : Nat}
|
||||
|
||||
/-- `G.CliqueFree n` means that `G` has no `n`-cliques. -/
|
||||
def CliqueFree (n : Nat) : Prop :=
|
||||
∀ t, ¬G.IsNClique n t
|
||||
|
||||
end CliqueFree
|
||||
|
||||
end SimpleGraph
|
||||
end Mathlib.Combinatorics.SimpleGraph.Clique
|
||||
|
||||
section Mathlib.Order.Partition.Finpartition
|
||||
open Finset
|
||||
|
||||
variable {α : Type*}
|
||||
|
||||
/-- A finite partition of `a : α` is a pairwise disjoint finite set of elements whose supremum is
|
||||
`a`. We forbid `⊥` as a part. -/
|
||||
structure Finpartition (a : α) where
|
||||
/-- The elements of the finite partition of `a` -/
|
||||
parts : Finset α
|
||||
|
||||
/-! ### Finite partitions of finsets -/
|
||||
|
||||
namespace Finpartition
|
||||
|
||||
variable [DecidableEq α] {s t u : Finset α} (P : Finpartition s) {a : α}
|
||||
|
||||
theorem existsUnique_mem (ha : a ∈ s) : ∃ t, t ∈ P.parts ∧ a ∈ t := by sorry
|
||||
|
||||
/-- The part of the finpartition that `a` lies in. -/
|
||||
def part (a : α) : Finset α := if ha : a ∈ s then choose (hp := P.existsUnique_mem ha) else .empty
|
||||
|
||||
section SetSetoid
|
||||
|
||||
/-- A setoid over a finite type induces a finpartition of the type's elements,
|
||||
where the parts are the setoid's equivalence classes. -/
|
||||
def ofSetSetoid (s : Setoid α) (x : Finset α) [DecidableRel s.r] : Finpartition x where
|
||||
parts := x.image fun a ↦ x.filter (s.r a ·)
|
||||
|
||||
end SetSetoid
|
||||
|
||||
section Setoid
|
||||
|
||||
variable [Fintype α]
|
||||
|
||||
/-- A setoid over a finite type induces a finpartition of the type's elements,
|
||||
where the parts are the setoid's equivalence classes. -/
|
||||
def ofSetoid (s : Setoid α) [DecidableRel s.r] : Finpartition (univ : Finset α) :=
|
||||
ofSetSetoid s univ
|
||||
|
||||
end Setoid
|
||||
|
||||
end Finpartition
|
||||
|
||||
end Mathlib.Order.Partition.Finpartition
|
||||
|
||||
open Finset
|
||||
|
||||
namespace SimpleGraph
|
||||
|
||||
variable {V : Type*} [Fintype V] {G : SimpleGraph V} [DecidableRel G.Adj] {n r : Nat}
|
||||
|
||||
variable (G) in
|
||||
/-- An `r + 1`-cliquefree graph is `r`-Turán-maximal if any other `r + 1`-cliquefree graph on
|
||||
the same vertex set has the same or fewer number of edges. -/
|
||||
def IsTuranMaximal (r : Nat) : Prop :=
|
||||
G.CliqueFree (r + 1) ∧ ∀ (H : SimpleGraph V) [DecidableRel H.Adj],
|
||||
H.CliqueFree (r + 1) → H.edgeFinset.card ≤ G.edgeFinset.card
|
||||
|
||||
namespace IsTuranMaximal
|
||||
|
||||
variable {s t u : V}
|
||||
|
||||
variable (h : G.IsTuranMaximal r)
|
||||
include h
|
||||
|
||||
/-- In a Turán-maximal graph, non-adjacency is an equivalence relation. -/
|
||||
theorem equivalence_not_adj : Equivalence (¬G.Adj · ·) where
|
||||
refl := sorry
|
||||
symm := sorry
|
||||
trans := sorry
|
||||
|
||||
/-- The non-adjacency setoid over the vertices of a Turán-maximal graph
|
||||
induced by `equivalence_not_adj`. -/
|
||||
def setoid : Setoid V := ⟨_, h.equivalence_not_adj⟩
|
||||
|
||||
instance : DecidableRel h.setoid.r :=
|
||||
inferInstanceAs <| DecidableRel (¬G.Adj · ·)
|
||||
|
||||
/-- The finpartition derived from `h.setoid`. -/
|
||||
def finpartition [DecidableEq V] : Finpartition (univ : Finset V) := Finpartition.ofSetoid h.setoid
|
||||
|
||||
theorem not_adj_iff_part_eq [DecidableEq V] :
|
||||
¬G.Adj s t ↔ h.finpartition.part s = h.finpartition.part t := by sorry
|
||||
|
||||
theorem card_parts_extracted_1_11 [DecidableEq V] :
|
||||
let fp := h.finpartition;
|
||||
fp.parts.card < (Finset.univ (α := V)).card ∧ fp.parts.card < r →
|
||||
∀ (x y : V),
|
||||
x ≠ y → fp.part x = fp.part y →
|
||||
∀ ⦃z : Finset V⦄, z.card = r → ∃ x ∈ ↑z, ∃ y ∈ ↑z, x ≠ y ∧ ¬G.Adj x y := by
|
||||
intro fp l x y hn he z zc
|
||||
simp [h.not_adj_iff_part_eq] ---- should work
|
||||
sorry
|
||||
|
||||
end IsTuranMaximal
|
||||
|
||||
end SimpleGraph
|
||||
Reference in New Issue
Block a user