feat: helper theorems for grind order (#10589)

This PR adds helper theorems for implementing  `grind order`
This commit is contained in:
Leonardo de Moura 2025-09-26 21:04:44 -07:00 committed by GitHub
parent 6d5efd79b9
commit 39beb25f16
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 284 additions and 0 deletions

View file

@ -24,3 +24,4 @@ public import Init.Grind.Attr
public import Init.Data.Int.OfNat -- This may not have otherwise been imported, breaking `grind` proofs.
public import Init.Grind.AC
public import Init.Grind.Injective
public import Init.Grind.Order

215
src/Init/Grind/Order.lean Normal file
View file

@ -0,0 +1,215 @@
/-
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.Grind.Ordered.Ring
import Init.Grind.Ring
public section
namespace Lean.Grind.Order
/-!
Helper theorems to assert constraints
-/
theorem le_of_eq {α} [LE α] [Std.IsPreorder α]
(a b : α) : a = b → a ≤ b := by
intro h; subst a; apply Std.IsPreorder.le_refl
theorem le_of_not_le {α} [LE α] [Std.IsLinearPreorder α]
(a b : α) : ¬ a ≤ b → b ≤ a := by
intro h
have := Std.IsLinearPreorder.le_total a b
cases this; contradiction; assumption
theorem lt_of_not_le {α} [LE α] [LT α] [Std.IsLinearPreorder α] [Std.LawfulOrderLT α]
(a b : α) : ¬ a ≤ b → b < a := by
intro h
rw [Std.LawfulOrderLT.lt_iff]
have := Std.IsLinearPreorder.le_total a b
cases this; contradiction; simp [*]
theorem le_of_not_lt {α} [LE α] [LT α] [Std.IsLinearPreorder α] [Std.LawfulOrderLT α]
(a b : α) : ¬ a < b → b ≤ a := by
rw [Std.LawfulOrderLT.lt_iff]
open Classical in
rw [Classical.not_and_iff_not_or_not, Classical.not_not]
intro h; cases h
next =>
have := Std.IsLinearPreorder.le_total a b
cases this; contradiction; assumption
next => assumption
theorem int_lt (x y k : Int) : x < y + k → x ≤ y + (k-1) := by
omega
/-!
Helper theorem for equality propagation
-/
theorem eq_of_le_of_le {α} [LE α] [Std.IsPartialOrder α] {a b : α} : a ≤ b → b ≤ a → a = b :=
Std.IsPartialOrder.le_antisymm _ _
/-!
Transitivity
-/
theorem le_trans {α} [LE α] [Std.IsPreorder α] {a b c : α} (h₁ : a ≤ b) (h₂ : b ≤ c) : a ≤ c :=
Std.IsPreorder.le_trans _ _ _ h₁ h₂
theorem lt_trans {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] {a b c : α} (h₁ : a < b) (h₂ : b < c) : a < c :=
Preorder.lt_trans h₁ h₂
theorem le_lt_trans {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] {a b c : α} (h₁ : a ≤ b) (h₂ : b < c) : a < c :=
Preorder.lt_of_le_of_lt h₁ h₂
theorem lt_le_trans {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] {a b c : α} (h₁ : a < b) (h₂ : b ≤ c) : a < c :=
Preorder.lt_of_lt_of_le h₁ h₂
theorem lt_unsat {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] (a : α) : a < a → False :=
Preorder.lt_irrefl a
/-!
Transitivity with offsets
-/
attribute [local instance] Ring.intCast
theorem le_trans_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b c : α) (k₁ k₂ k : Int) (h₁ : a ≤ b + k₁) (h₂ : b ≤ c + k₂) : k == k₂ + k₁ → a ≤ c + k := by
intro h; simp at h; subst k
replace h₂ := OrderedAdd.add_le_left_iff (M := α) k₁ |>.mp h₂
have := le_trans h₁ h₂
simp [Ring.intCast_add, ← Semiring.add_assoc, this]
theorem lt_trans_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b c : α) (k₁ k₂ k : Int) (h₁ : a < b + k₁) (h₂ : b < c + k₂) : k == k₂ + k₁ → a < c + k := by
intro h; simp at h; subst k
replace h₂ := OrderedAdd.add_lt_left_iff (M := α) k₁ |>.mp h₂
have := lt_trans h₁ h₂
simp [Ring.intCast_add, ← Semiring.add_assoc, this]
theorem le_lt_trans_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b c : α) (k₁ k₂ k : Int) (h₁ : a ≤ b + k₁) (h₂ : b < c + k₂) : k == k₂ + k₁ → a < c + k := by
intro h; simp at h; subst k
replace h₂ := OrderedAdd.add_lt_left_iff (M := α) k₁ |>.mp h₂
have := le_lt_trans h₁ h₂
simp [Ring.intCast_add, ← Semiring.add_assoc, this]
theorem lt_le_trans_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b c : α) (k₁ k₂ k : Int) (h₁ : a < b + k₁) (h₂ : b ≤ c + k₂) : k == k₂ + k₁ → a < c + k := by
intro h; simp at h; subst k
replace h₂ := OrderedAdd.add_le_left_iff (M := α) k₁ |>.mp h₂
have := lt_le_trans h₁ h₂
simp [Ring.intCast_add, ← Semiring.add_assoc, this]
/-!
Unsat detection
-/
theorem le_unsat_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a : α) (k : Int) : k.blt' 0 → a ≤ a + k → False := by
simp; intro h₁ h₂
replace h₂ := OrderedAdd.add_le_left_iff (-a) |>.mp h₂
rw [AddCommGroup.add_neg_cancel, Semiring.add_assoc, Semiring.add_comm _ (-a)] at h₂
rw [← Semiring.add_assoc, AddCommGroup.add_neg_cancel, Semiring.add_comm, Semiring.add_zero] at h₂
rw [← Ring.intCast_zero] at h₂
replace h₂ := OrderedRing.le_of_intCast_le_intCast _ _ h₂
omega
theorem lt_unsat_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a : α) (k : Int) : k.ble' 0 → a < a + k → False := by
simp; intro h₁ h₂
replace h₂ := OrderedAdd.add_lt_left_iff (-a) |>.mp h₂
rw [AddCommGroup.add_neg_cancel, Semiring.add_assoc, Semiring.add_comm _ (-a)] at h₂
rw [← Semiring.add_assoc, AddCommGroup.add_neg_cancel, Semiring.add_comm, Semiring.add_zero] at h₂
rw [← Ring.intCast_zero] at h₂
replace h₂ := OrderedRing.lt_of_intCast_lt_intCast _ _ h₂
omega
/-!
Helper theorems
-/
private theorem add_lt_add_of_le_of_lt {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
{a b c d : α} (hab : a ≤ b) (hcd : c < d) : a + c < b + d :=
lt_le_trans (OrderedAdd.add_lt_right a hcd) (OrderedAdd.add_le_left hab d)
private theorem add_lt_add_of_lt_of_le {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
{a b c d : α} (hab : a < b) (hcd : c ≤ d) : a + c < b + d :=
le_lt_trans (OrderedAdd.add_le_right a hcd) (OrderedAdd.add_lt_left hab d)
/-! Theorems for propagating constraints to `True` -/
theorem le_eq_true_of_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : k₁.ble' k₂ → a ≤ b + k₁ → (a ≤ b + k₂) = True := by
simp; intro h₁ h₂
replace h₁ : 0 ≤ k₂ - k₁ := by omega
replace h₁ := OrderedRing.nonneg_intCast_of_nonneg (R := α) _ h₁
replace h₁ := OrderedAdd.add_le_add h₂ h₁
rw [Semiring.add_zero, Semiring.add_assoc, Int.sub_eq_add_neg, Int.add_comm] at h₁
rw [Ring.intCast_add, Ring.intCast_neg, ← Semiring.add_assoc (k₁ : α)] at h₁
rw [AddCommGroup.add_neg_cancel, Semiring.add_comm 0, Semiring.add_zero] at h₁
assumption
theorem le_eq_true_of_lt_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : k₁.ble' k₂ → a < b + k₁ → (a ≤ b + k₂) = True := by
intro h₁ h₂
replace h₂ := Std.le_of_lt h₂
apply le_eq_true_of_le_k <;> assumption
theorem lt_eq_true_of_lt_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : k₁.ble' k₂ → a < b + k₁ → (a < b + k₂) = True := by
simp; intro h₁ h₂
replace h₁ : 0 ≤ k₂ - k₁ := by omega
replace h₁ := OrderedRing.nonneg_intCast_of_nonneg (R := α) _ h₁
replace h₁ := add_lt_add_of_le_of_lt h₁ h₂
rw [Semiring.add_comm, Semiring.add_zero, Semiring.add_comm, Semiring.add_assoc, Int.sub_eq_add_neg, Int.add_comm] at h₁
rw [Ring.intCast_add, Ring.intCast_neg, ← Semiring.add_assoc (k₁ : α)] at h₁
rw [AddCommGroup.add_neg_cancel, Semiring.add_comm 0, Semiring.add_zero] at h₁
assumption
theorem lt_eq_true_of_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : k₁.blt' k₂ → a ≤ b + k₁ → (a < b + k₂) = True := by
simp; intro h₁ h₂
replace h₁ : 0 < k₂ - k₁ := by omega
replace h₁ := OrderedRing.pos_intCast_of_pos (R := α) _ h₁
replace h₁ := add_lt_add_of_le_of_lt h₂ h₁
rw [Semiring.add_zero, Semiring.add_assoc, Int.sub_eq_add_neg, Int.add_comm] at h₁
rw [Ring.intCast_add, Ring.intCast_neg, ← Semiring.add_assoc (k₁ : α)] at h₁
rw [AddCommGroup.add_neg_cancel, Semiring.add_comm 0, Semiring.add_zero] at h₁
assumption
/-! Theorems for propagating constraints to `False` -/
theorem le_eq_false_of_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : (k₂ + k₁).blt' 0 → a ≤ b + k₁ → (b ≤ a + k₂) = False := by
intro h₁; simp; intro h₂ h₃
have h := le_trans_k _ _ _ _ _ (k₂ + k₁) h₂ h₃
simp at h
apply le_unsat_k _ _ h₁ h
theorem lt_eq_false_of_le_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : (k₂ + k₁).ble' 0 → a ≤ b + k₁ → (b < a + k₂) = False := by
intro h₁; simp; intro h₂ h₃
have h := le_lt_trans_k _ _ _ _ _ (k₂ + k₁) h₂ h₃
simp at h
apply lt_unsat_k _ _ h₁ h
theorem lt_eq_false_of_lt_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : (k₂ + k₁).ble' 0 → a < b + k₁ → (b < a + k₂) = False := by
intro h₁; simp; intro h₂ h₃
have h := lt_trans_k _ _ _ _ _ (k₂ + k₁) h₂ h₃
simp at h
apply lt_unsat_k _ _ h₁ h
theorem le_eq_false_of_lt_k {α} [LE α] [LT α] [Std.LawfulOrderLT α] [Std.IsPreorder α] [Ring α] [OrderedRing α]
(a b : α) (k₁ k₂ : Int) : (k₂ + k₁).ble' 0 → a < b + k₁ → (b ≤ a + k₂) = False := by
intro h₁; simp; intro h₂ h₃
have h := lt_le_trans_k _ _ _ _ _ (k₂ + k₁) h₂ h₃
simp at h
apply lt_unsat_k _ _ h₁ h
end Lean.Grind.Order

View file

@ -73,6 +73,9 @@ theorem add_lt_left_iff {a b : M} (c : M) : a < b ↔ a + c < b + c := by
theorem add_lt_right_iff {a b : M} (c : M) : a < b ↔ c + a < c + b := by
rw [add_comm c a, add_comm c b, add_lt_left_iff]
theorem add_lt_add {a b c d : M} (hab : a < b) (hcd : c < d) : a + c < b + d :=
Preorder.lt_trans (add_lt_right a hcd) (add_lt_left hab d)
end
section

View file

@ -133,6 +133,71 @@ theorem lt_of_intCast_lt_intCast (a b : Int) : (a : R) < (b : R) → a < b := by
replace h := lt_of_natCast_lt_natCast _ _ h
omega
theorem natCast_le_natCast_of_le (a b : Nat) : a ≤ b → (a : R) ≤ (b : R) := by
induction a generalizing b <;> cases b <;> simp
next => simp [Semiring.natCast_zero, Std.IsPreorder.le_refl]
next n =>
have := ofNat_nonneg (R := R) n
simp [Semiring.ofNat_eq_natCast] at this
rw [Semiring.natCast_zero] at this
simp [Semiring.natCast_zero, Semiring.natCast_add, Semiring.natCast_one]
replace this := OrderedAdd.add_le_left_iff 1 |>.mp this
rw [Semiring.add_comm, Semiring.add_zero] at this
replace this := Std.lt_of_lt_of_le zero_lt_one this
exact Std.le_of_lt this
next n ih m =>
intro h
replace ih := ih _ h
simp [Semiring.natCast_add, Semiring.natCast_one]
exact OrderedAdd.add_le_left_iff _ |>.mp ih
theorem natCast_lt_natCast_of_lt (a b : Nat) : a < b → (a : R) < (b : R) := by
induction a generalizing b <;> cases b <;> simp
next n =>
have := ofNat_nonneg (R := R) n
simp [Semiring.ofNat_eq_natCast] at this
rw [Semiring.natCast_zero] at this
simp [Semiring.natCast_zero, Semiring.natCast_add, Semiring.natCast_one]
replace this := OrderedAdd.add_le_left_iff 1 |>.mp this
rw [Semiring.add_comm, Semiring.add_zero] at this
exact Std.lt_of_lt_of_le zero_lt_one this
next n ih m =>
intro h
replace ih := ih _ h
simp [Semiring.natCast_add, Semiring.natCast_one]
exact OrderedAdd.add_lt_left_iff _ |>.mp ih
theorem pos_natCast_of_pos (a : Nat) : 0 < a → 0 < (a : R) := by
induction a
next => simp
next n ih =>
simp; cases n
next => simp +arith; rw [Semiring.natCast_one]; apply zero_lt_one
next =>
simp at ih
replace ih := OrderedAdd.add_lt_add ih zero_lt_one
rw [Semiring.add_zero, ← Semiring.natCast_one, ← Semiring.natCast_add] at ih
assumption
theorem pos_intCast_of_pos (a : Int) : 0 < a → 0 < (a : R) := by
cases a
next n =>
intro h
replace h : 0 < n := by cases n; simp at h; simp
replace h := pos_natCast_of_pos (R := R) _ h
rw [Int.ofNat_eq_natCast, Ring.intCast_natCast]
assumption
next => omega
theorem nonneg_intCast_of_nonneg (a : Int) : 0 ≤ a → 0 ≤ (a : R) := by
cases a
next n =>
intro; rw [Int.ofNat_eq_natCast, Ring.intCast_natCast]
have := ofNat_nonneg (R := R) n
rw [Semiring.ofNat_eq_natCast] at this
assumption
next => omega
instance [Ring R] [LE R] [LT R] [LawfulOrderLT R] [IsPreorder R] [OrderedRing R] :
IsCharP R 0 := IsCharP.mk' _ _ <| by
intro x