@@ -229,4 +229,204 @@ instance : LawfulBEq Poly where
229229
230230attribute [local simp] Poly.denote'_eq_denote
231231
232+ def Poly.leadCoeff (p : Poly) : Int :=
233+ match p with
234+ | .add a _ _ => a
235+ | _ => 1
236+
237+ open IntModule.IsOrdered
238+
239+ /-!
240+ Helper theorems for conflict resolution during model construction.
241+ -/
242+
243+ private theorem le_add_le {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] {a b : α}
244+ (h₁ : a ≤ 0 ) (h₂ : b ≤ 0 ) : a + b ≤ 0 := by
245+ replace h₁ := add_le_left h₁ b; simp at h₁
246+ exact Preorder.le_trans h₁ h₂
247+
248+ private theorem le_add_lt {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] {a b : α}
249+ (h₁ : a ≤ 0 ) (h₂ : b < 0 ) : a + b < 0 := by
250+ replace h₁ := add_le_left h₁ b; simp at h₁
251+ exact Preorder.lt_of_le_of_lt h₁ h₂
252+
253+ private theorem lt_add_lt {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] {a b : α}
254+ (h₁ : a < 0 ) (h₂ : b < 0 ) : a + b < 0 := by
255+ replace h₁ := add_lt_left h₁ b; simp at h₁
256+ exact Preorder.lt_trans h₁ h₂
257+
258+ private theorem coe_natAbs_nonneg (a : Int) : (a.natAbs : Int) ≥ 0 := by
259+ exact Int.natCast_nonneg a.natAbs
260+
261+ def le_le_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
262+ let a₁ := p₁.leadCoeff.natAbs
263+ let a₂ := p₂.leadCoeff.natAbs
264+ p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
265+
266+ theorem le_le_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
267+ : le_le_combine_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≤ 0 → p₃.denote' ctx ≤ 0 := by
268+ simp [le_le_combine_cert]; intro _ h₁ h₂; subst p₃; simp
269+ replace h₁ := hmul_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
270+ replace h₂ := hmul_nonpos (coe_natAbs_nonneg p₁.leadCoeff) h₂
271+ exact le_add_le h₁ h₂
272+
273+ def le_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
274+ let a₁ := p₁.leadCoeff.natAbs
275+ let a₂ := p₂.leadCoeff.natAbs
276+ a₁ > (0 : Int) && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
277+
278+ theorem le_lt_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
279+ : le_lt_combine_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
280+ simp [-Int.natAbs_pos, -Int.ofNat_pos, le_lt_combine_cert]; intro hp _ h₁ h₂; subst p₃; simp
281+ replace h₁ := hmul_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
282+ replace h₂ := hmul_neg (↑p₁.leadCoeff.natAbs) h₂ |>.mp hp
283+ exact le_add_lt h₁ h₂
284+
285+ theorem le_eq_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
286+ : le_le_combine_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx = 0 → p₃.denote' ctx ≤ 0 := by
287+ simp [le_le_combine_cert]; intro _ h₁ h₂; subst p₃; simp [h₂]
288+ replace h₁ := hmul_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
289+ assumption
290+
291+ def lt_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
292+ let a₁ := p₁.leadCoeff.natAbs
293+ let a₂ := p₂.leadCoeff.natAbs
294+ a₂ > (0 : Int) && a₁ > (0 : Int) && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
295+
296+ theorem lt_lt_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
297+ : lt_lt_combine_cert p₁ p₂ p₃ → p₁.denote' ctx < 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
298+ simp [-Int.natAbs_pos, -Int.ofNat_pos, lt_lt_combine_cert]; intro hp₁ hp₂ _ h₁ h₂; subst p₃; simp
299+ replace h₁ := hmul_neg (↑p₂.leadCoeff.natAbs) h₁ |>.mp hp₁
300+ replace h₂ := hmul_neg (↑p₁.leadCoeff.natAbs) h₂ |>.mp hp₂
301+ exact lt_add_lt h₁ h₂
302+
303+ def lt_eq_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
304+ let a₁ := p₁.leadCoeff.natAbs
305+ let a₂ := p₂.leadCoeff.natAbs
306+ a₂ > (0 : Int) && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
307+
308+ theorem lt_eq_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
309+ : lt_eq_combine_cert p₁ p₂ p₃ → p₁.denote' ctx < 0 → p₂.denote' ctx = 0 → p₃.denote' ctx < 0 := by
310+ simp [-Int.natAbs_pos, -Int.ofNat_pos, lt_eq_combine_cert]; intro hp₁ _ h₁ h₂; subst p₃; simp [h₂]
311+ replace h₁ := hmul_neg (↑p₂.leadCoeff.natAbs) h₁ |>.mp hp₁
312+ assumption
313+
314+ theorem eq_eq_combine {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
315+ : le_le_combine_cert p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx = 0 → p₃.denote' ctx = 0 := by
316+ simp [le_le_combine_cert]; intro _ h₁ h₂; subst p₃; simp [h₁, h₂]
317+
318+ def diseq_split_cert (p₁ p₂ : Poly) : Bool :=
319+ p₂ == p₁.mul (-1 )
320+
321+ -- We need `LinearOrder` to use `trichotomy`
322+ theorem diseq_split {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (p₁ p₂ : Poly)
323+ : diseq_split_cert p₁ p₂ → p₁.denote' ctx ≠ 0 → p₁.denote' ctx < 0 ∨ p₂.denote' ctx < 0 := by
324+ simp [diseq_split_cert]; intro _ h₁; subst p₂; simp
325+ cases LinearOrder.trichotomy (p₁.denote ctx) 0
326+ next h => exact Or.inl h
327+ next h =>
328+ apply Or.inr
329+ simp [h₁] at h
330+ rw [← neg_pos_iff, neg_hmul, neg_neg, one_hmul]; assumption
331+
332+ def eq_diseq_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
333+ let a₁ := p₁.leadCoeff.natAbs
334+ let a₂ := p₂.leadCoeff.natAbs
335+ a₁ ≠ 0 && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
336+
337+ theorem eq_diseq_combine {α} [IntModule α] [NoNatZeroDivisors α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
338+ : eq_diseq_combine_cert p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx ≠ 0 → p₃.denote' ctx ≠ 0 := by
339+ simp [- Int.natAbs_eq_zero, -Int.natCast_eq_zero, eq_diseq_combine_cert]; intro hne _ h₁ h₂; subst p₃
340+ simp [h₁, h₂]; intro h
341+ have := no_nat_zero_divisors (p₁.leadCoeff.natAbs) (p₂.denote ctx) hne h
342+ contradiction
343+
344+ def eq_diseq_combine_cert' (p₁ p₂ p₃ : Poly) (k : Int) : Bool :=
345+ p₃ == (p₁.mul k |>.combine p₂)
346+
347+ /-
348+ Special case of `eq_diseq_combine` where leading coefficient `c₁` of `p₁` is `-k*c₂`, where
349+ `c₂` is the leading coefficient of `p₂`.
350+ -/
351+ theorem eq_diseq_combine' {α} [IntModule α] (ctx : Context α) (p₁ p₂ p₃ : Poly) (k : Int)
352+ : eq_diseq_combine_cert' p₁ p₂ p₃ k → p₁.denote' ctx = 0 → p₂.denote' ctx ≠ 0 → p₃.denote' ctx ≠ 0 := by
353+ simp [eq_diseq_combine_cert']; intro _ h₁ h₂; subst p₃
354+ simp [h₁, h₂]
355+
356+ /-!
357+ Helper theorems for internalizing facts into the linear arithmetic procedure
358+ -/
359+
360+ def norm_cert (lhs rhs : Expr) (p : Poly) :=
361+ p == (lhs.sub rhs).norm
362+
363+ theorem eq_norm {α} [IntModule α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
364+ : norm_cert lhs rhs p → lhs.denote ctx = rhs.denote ctx → p.denote ctx = 0 := by
365+ simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
366+
367+ theorem diseq_norm {α} [IntModule α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
368+ : norm_cert lhs rhs p → lhs.denote ctx ≠ rhs.denote ctx → p.denote ctx ≠ 0 := by
369+ simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
370+ intro h
371+ replace h := congrArg (rhs.denote ctx + ·) h; simp [sub_eq_add_neg] at h
372+ rw [add_left_comm, ← sub_eq_add_neg, sub_self, add_zero] at h
373+ contradiction
374+
375+ theorem le_norm {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
376+ : norm_cert lhs rhs p → lhs.denote ctx ≤ rhs.denote ctx → p.denote ctx ≤ 0 := by
377+ simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
378+ replace h₁ := add_le_left h₁ (-rhs.denote ctx)
379+ simp [← sub_eq_add_neg, sub_self] at h₁
380+ assumption
381+
382+ theorem lt_norm {α} [IntModule α] [Preorder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
383+ : norm_cert lhs rhs p → lhs.denote ctx < rhs.denote ctx → p.denote ctx < 0 := by
384+ simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
385+ replace h₁ := add_lt_left h₁ (-rhs.denote ctx)
386+ simp [← sub_eq_add_neg, sub_self] at h₁
387+ assumption
388+
389+ private theorem le_of_not_lt {α} [LinearOrder α] {a b : α} (h : ¬ a < b) : b ≤ a := by
390+ cases LinearOrder.trichotomy a b
391+ next => contradiction
392+ next h => apply PartialOrder.le_iff_lt_or_eq.mpr; cases h <;> simp [*]
393+
394+ private theorem lt_of_not_le {α} [LinearOrder α] {a b : α} (h : ¬ a ≤ b) : b < a := by
395+ cases LinearOrder.trichotomy a b
396+ next h₁ h₂ => have := Preorder.lt_iff_le_not_le.mp h₂; simp [h] at this
397+ next h =>
398+ cases h
399+ next h => subst a; exact False.elim <| h (Preorder.le_refl b)
400+ next => assumption
401+
402+ theorem not_le_norm {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
403+ : norm_cert rhs lhs p → ¬ lhs.denote ctx ≤ rhs.denote ctx → p.denote ctx < 0 := by
404+ simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
405+ replace h₁ := lt_of_not_le h₁
406+ replace h₁ := add_lt_left h₁ (-lhs.denote ctx)
407+ simp [← sub_eq_add_neg, sub_self] at h₁
408+ assumption
409+
410+ theorem not_lt_norm {α} [IntModule α] [LinearOrder α] [IntModule.IsOrdered α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
411+ : norm_cert rhs lhs p → ¬ lhs.denote ctx < rhs.denote ctx → p.denote ctx ≤ 0 := by
412+ simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
413+ replace h₁ := le_of_not_lt h₁
414+ replace h₁ := add_le_left h₁ (-lhs.denote ctx)
415+ simp [← sub_eq_add_neg, sub_self] at h₁
416+ assumption
417+
418+ /-!
419+ Helper theorems for closing the goal
420+ -/
421+
422+ theorem diseq_unsat {α} [IntModule α] (ctx : Context α) : (Poly.nil).denote ctx ≠ 0 → False := by
423+ simp [Poly.denote]
424+
425+ theorem lt_unsat {α} [IntModule α] [Preorder α] (ctx : Context α) : (Poly.nil).denote ctx < 0 → False := by
426+ simp [Poly.denote]; intro h
427+ have := Preorder.lt_iff_le_not_le.mp h
428+ simp at this
429+
430+ -- TODO: support for the special variable representing (1 : α). Example: `3 * (1 : α) ≤ 0`
431+
232432end Lean.Grind.Linarith
0 commit comments