example : True := by
  fail_if_success omega
  trivial

-- set_option trace.omega true
example (_ : (1 : Int) < (0 : Int)) : False := by omega

example (_ : (0 : Int) < (0 : Int)) : False := by omega
example (_ : (0 : Int) < (1 : Int)) : True := by (fail_if_success omega); trivial

example {x : Int} (_ : 0 ≤ x) (_ : x ≤ 1) : True := by (fail_if_success omega); trivial
example {x : Int} (_ : 0 ≤ x) (_ : x ≤ -1) : False := by omega

example {x : Int} (_ : x % 2 < x - 2 * (x / 2)) : False := by omega
example {x : Int} (_ : x % 2 > 5) : False := by omega

example {x : Int} (_ : 2 * (x / 2) > x) : False := by omega
example {x : Int} (_ : 2 * (x / 2) ≤ x - 2) : False := by omega

example {x : Nat} : x / 0 = 0 := by omega
example {x : Int} : x / 0 = 0 := by omega

example {x : Int} : x / 2 + x / (-2) = 0 := by omega

example {x : Nat} (_ : x ≠ 0) : 0 < x := by omega

example (_ : a ≤ c) (_ : b ≤ c) : a < Nat.succ c := by omega

example (_ : 7 < 3) : False := by omega
example (_ : 0 < 0) : False := by omega

example {x : Nat} (_ : x > 7) (_ : x < 3) : False := by omega
example {x : Nat} (_ : x ≥ 7) (_ : x ≤ 3) : False := by omega

example {x y : Nat} (_ : x + y > 10) (_ : x < 5) (_ : y < 5) : False := by omega

example {x y : Int} (_ : x + y > 10) (_ : 2 * x < 11) (_ : y < 5) : False := by omega
example {x y : Nat} (_ : x + y > 10) (_ : 2 * x < 11) (_ : y < 5) : False := by omega

example {x y : Int} (_ : 2 * x + 4 * y = 5) : False := by omega
example {x y : Nat} (_ : 2 * x + 4 * y = 5) : False := by omega

example {x y : Int} (_ : 6 * x + 7 * y = 5) : True := by (fail_if_success omega); trivial

example {x y : Nat} (_ : 6 * x + 7 * y = 5) : False := by omega

example {x y : Nat} (_ : x * 6 + y * 7 = 5) : False := by omega
example {x y : Nat} (_ : 2 * (3 * x) + y * 7 = 5) : False := by omega
example {x y : Nat} (_ : 2 * x * 3 + y * 7 = 5) : False := by omega
example {x y : Nat} (_ : 2 * 3 * x + y * 7 = 5) : False := by omega

example {x : Nat} (_ : x < 0) : False := by omega

example {x y z : Int} (_ : x + y > z) (_ : x < 0) (_ : y < 0) (_ : z > 0) : False := by omega

example {x y : Nat} (_ : x - y = 0) (_ : x > y) : False := by
  fail_if_success omega (config := { splitNatSub := false })
  omega

example {x y z : Int} (_ : x - y - z = 0) (_ : x > y + z) : False := by omega

example {x y z : Nat} (_ : x - y - z = 0) (_ : x > y + z) : False := by omega

example {a b c d e f : Nat} (_ : a - b - c - d - e - f = 0) (_ : a > b + c + d + e + f) :
    False := by
  omega

example {x y : Nat} (h₁ : x - y ≤ 0) (h₂ : y < x) : False := by omega

example {x y : Int} (_ : x / 2 - y / 3 < 1) (_ : 3 * x ≥ 2 * y + 6) : False := by omega

example {x y : Nat} (_ : x / 2 - y / 3 < 1) (_ : 3 * x ≥ 2 * y + 6) : False := by omega

example {x y : Nat} (_ : x / 2 - y / 3 < 1) (_ : 3 * x ≥ 2 * y + 4) : False := by omega

example {x y : Nat} (_ : x / 2 - y / 3 < x % 2) (_ : 3 * x ≥ 2 * y + 4) : False := by omega

example {x : Int} (h₁ : 5 ≤ x) (h₂ : x ≤ 4) : False := by omega

example {x : Nat} (h₁ : 5 ≤ x) (h₂ : x ≤ 4) : False := by omega

example {x : Nat} (h₁ : x / 3 ≥ 2) (h₂ : x < 6) : False := by omega

example {x : Int} {y : Nat} (_ : 0 < x) (_ : x + y ≤ 0) : False := by omega

example {a b c : Nat} (_ : a - (b - c) ≤ 5) (_ : b ≥ c + 3) (_ : a + c ≥ b + 6) : False := by omega

example {x : Nat} : 1 < (1 + ((x + 1 : Nat) : Int) + 2) / 2 := by omega

example {x : Nat} : (x + 4) / 2 ≤ x + 2 := by omega

example {x : Int} {m : Nat} (_ : 0 < m) (_ : ¬x % ↑m < (↑m + 1) / 2) : -↑m / 2 ≤ x % ↑m - ↑m := by
  omega

example (h : (7 : Int) = 0) : False := by omega

example (h : (7 : Int) ≤ 0) : False := by omega

example (h : (-7 : Int) + 14 = 0) : False := by omega

example (h : (-7 : Int) + 14 ≤ 0) : False := by omega

example (h : (1 : Int) + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 = 0) : False := by
  omega

example (h : (7 : Int) - 14 = 0) : False := by omega

example (h : (14 : Int) - 7 ≤ 0) : False := by omega

example (h : (1 : Int) - 1 + 1 - 1 + 1 - 1 + 1 - 1 + 1 - 1 + 1 - 1 + 1 - 1 + 1 = 0) : False := by
  omega

example (h : -(7 : Int) = 0) : False := by omega

example (h : -(-7 : Int) ≤ 0) : False := by omega

example (h : 2 * (7 : Int) = 0) : False := by omega

example (h : (7 : Int) < 0) : False := by omega

example {x : Int} (h : x + x + 1 = 0) : False := by omega

example {x : Int} (h : 2 * x + 1 = 0) : False := by omega

example {x y : Int} (h : x + x + y + y + 1 = 0) : False := by omega

example {x y : Int} (h : 2 * x + 2 * y + 1 = 0) : False := by omega

example {x : Int} (h₁ : 0 ≤ -7 + x) (h₂ : 0 ≤ 3 - x) : False := by omega

example {x : Int} (h₁ : 0 ≤ -7 + x) (h₂ : 0 < 4 - x) : False := by omega

example {x : Int} (h₁ : 0 ≤ 2 * x + 1) (h₂ : 2 * x + 1 ≤ 0) : False := by omega

example {x : Int} (h₁ : 0 < 2 * x + 2) (h₂ : 2 * x + 1 ≤ 0) : False := by omega

example {x y : Int} (h₁ : 0 ≤ 2 * x + 1) (h₂ : x = y) (h₃ : 2 * y + 1 ≤ 0) : False := by omega

example {x y z : Int} (h₁ : 0 ≤ 2 * x + 1) (h₂ : x = y) (h₃ : y = z) (h₄ : 2 * z + 1 ≤ 0) :
    False := by omega

example {x1 x2 x3 x4 x5 x6 : Int} (h : 0 ≤ 2 * x1 + 1) (h : x1 = x2) (h : x2 = x3) (h : x3 = x4)
    (h : x4 = x5) (h : x5 = x6) (h : 2 * x6 + 1 ≤ 0) : False := by omega

example {x : Int} (_ : 1 ≤ -3 * x) (_ : 1 ≤ 2 * x) : False := by omega

example {x y : Int} (_ : 2 * x + 3 * y = 0) (_ : 1 ≤ x) (_ : 1 ≤ y) : False := by omega

example {x y z : Int} (_ : 2 * x + 3 * y = 0) (_ : 3 * y + 4 * z = 0) (_ : 1 ≤ x) (_ : 1 ≤ -z) :
    False := by omega

example {x y z : Int} (_ : 2 * x + 3 * y + 4 * z = 0) (_ : 1 ≤ x + y) (_ : 1 ≤ y + z)
    (_ : 1 ≤ x + z) : False := by omega

example {x y : Int} (_ : 1 ≤ 3 * x) (_ : y ≤ 2) (_ : 6 * x - 2 ≤ y) : False := by omega

example {x y : Int} (_ : y = x) (_ : 0 ≤ x - 2 * y) (_ : x - 2 * y ≤ 1) (_ : 1 ≤ x) : False := by
  omega
example {x y : Int} (_ : y = x) (_ : 0 ≤ x - 2 * y) (_ : x - 2 * y ≤ 1) (_ : x ≥ 1) : False := by
  omega
example {x y : Int} (_ : y = x) (_ : 0 ≤ x - 2 * y) (_ : x - 2 * y ≤ 1) (_ : 0 < x) : False := by
  omega
example {x y : Int} (_ : y = x) (_ : 0 ≤ x - 2 * y) (_ : x - 2 * y ≤ 1) (_ : x > 0) : False := by
  omega

example {x : Nat} (_ : 10 ∣ x) (_ : ¬ 5 ∣ x) : False := by omega
example {x y : Nat} (_ : 5 ∣ x) (_ : ¬ 10 ∣ x) (_ : y = 7) (_ : x - y ≤ 2) (_ : x ≥ 6) : False := by
  omega

example (x : Nat) : x % 4 - x % 8 = 0 := by omega

example {n : Nat} (_ : n > 0) : (2*n - 1) % 2 = 1 := by omega

example (x : Int) (_ : x > 0 ∧ x < -1) : False := by omega
example (x : Int) (_ : x > 7) : x < 0 ∨ x > 3 := by omega

example (_ : ∃ n : Nat, n < 0) : False := by omega
example (_ : { x : Int // x < 0 ∧ x > 0 }) : False := by omega
example {x y : Int} (_ : x < y) (z : { z : Int // y ≤ z ∧ z ≤ x }) : False := by omega

example (a b c d e : Int)
    (ha : 2 * a + b + c + d + e = 4)
    (hb : a + 2 * b + c + d + e = 5)
    (hc : a + b + 2 * c + d + e = 6)
    (hd : a + b + c + 2 * d + e = 7)
    (he : a + b + c + d + 2 * e = 8) : e = 3 := by omega

example (a b c d e : Int)
    (ha : 2 * a + b + c + d + e = 4)
    (hb : a + 2 * b + c + d + e = 5)
    (hc : a + b + 2 * c + d + e = 6)
    (hd : a + b + c + 2 * d + e = 7)
    (he : a + b + c + d + 2 * e = 8 ∨ e = 3) : e = 3 := by
  fail_if_success omega (config := { splitDisjunctions := false })
  omega

example {x : Int} (h : x = 7) : x.natAbs = 7 := by
  fail_if_success omega (config := { splitNatAbs := false })
  fail_if_success omega (config := { splitDisjunctions := false })
  omega

example {x y : Int} (_ : (x - y).natAbs < 3) (_ : x < 5) (_ : y > 15) : False := by
  omega

example {a b : Int} (h : a < b) (w : b < a) : False := by omega

example (_e b c a v0 v1 : Int) (_h1 : v0 = 5 * a) (_h2 : v1 = 3 * b) (h3 : v0 + v1 + c = 10) :
    v0 + 5 + (v1 - 3) + (c - 2) = 10 := by omega

example (h : (1 : Int) < 0) (_ : ¬ (37 : Int) < 42) (_ : True) (_ : (-7 : Int) < 5) :
    (3 : Int) < 7 := by omega

example (A B : Int) (h : 0 < A * B) : 0 < 8 * (A * B) := by omega

example (A B : Nat) (h : 7 < A * B) : 0 < A*B/8 := by omega
example (A B : Int) (h : 7 < A * B) : 0 < A*B/8 := by omega

example (ε : Int) (h1 : ε > 0) : ε / 2 + ε / 3 + ε / 7 < ε := by omega

example (x y z : Int) (h1 : 2*x < 3*y) (h2 : -4*x + z/2 < 0) (h3 : 12*y - z < 0) : False := by omega

example (ε : Int) (h1 : ε > 0) : ε / 2 < ε := by omega

example (ε : Int) (_ : ε > 0) : ε - 2 ≤ ε / 3 + ε / 3 + ε / 3 := by omega
example (ε : Int) (_ : ε > 0) : ε / 3 + ε / 3 + ε / 3 ≤ ε := by omega
example (ε : Int) (_ : ε > 0) : ε - 2 ≤ ε / 3 + ε / 3 + ε / 3 ∧ ε / 3 + ε / 3 + ε / 3 ≤ ε := by
  omega

example (x : Int) (h : 0 < x) : 0 < x / 1 := by omega

example (x : Int) (h : 5 < x) : 0 < x/2/3 := by omega

example (_a b _c : Nat) (h2 : b + 2 > 3 + b) : False := by omega
example (_a b _c : Int) (h2 : b + 2 > 3 + b) : False := by omega

example (g v V c h : Int) (_ : h = 0) (_ : v = V) (_ : V > 0) (_ : g > 0)
    (_ : 0 ≤ c) (_ : c < 1) : v ≤ V := by omega

example (x y z : Int) (h1 : 2 * x < 3 * y) (h2 : -4 * x + 2 * z < 0) (h3 : 12 * y - 4 * z < 0) :
    False := by
  omega

example (x y z : Int) (h1 : 2 * x < 3 * y) (h2 : -4 * x + 2 * z < 0) (_h3 : x * y < 5)
    (h3 : 12 * y - 4 * z < 0) : False := by omega

example (a b c : Int) (h1 : a > 0) (h2 : b > 5) (h3 : c < -10) (h4 : a + b - c < 3) : False := by
  omega

example (_ b _ : Int) (h2 : b > 0) (h3 : ¬ b ≥ 0) : False := by
  omega

example (x y z : Int) (hx : x ≤ 3 * y) (h2 : y ≤ 2 * z) (h3 : x ≥ 6 * z) : x = 3 * y := by
  omega

example (x y z : Int) (h1 : 2 * x < 3 * y) (h2 : -4 * x + 2 * z < 0) (_h3 : x * y < 5) :
    ¬ 12 * y - 4 * z < 0 := by
  omega

example (x y z : Int) (hx : ¬ x > 3 * y) (h2 : ¬ y > 2 * z) (h3 : x ≥ 6 * z) : x = 3 * y := by
  omega

example (x y : Int) (h : 6 + ((x + 4) * x + (6 + 3 * y) * y) = 3) (h' : (x + 4) * x ≥ 0)
    (h'' : (6 + 3 * y) * y ≥ 0) : False := by omega

example (a : Int) (ha : 0 ≤ a) : 0 * 0 ≤ 2 * a := by omega

example (x y : Int) (h : x < y) : x ≠ y := by omega

example (x y : Int) (h : x < y) : ¬ x = y := by omega

example (prime : Nat → Prop) (x y z : Int) (h1 : 2 * x + ((-3) * y) < 0) (h2 : (-4) * x + 2*  z < 0)
    (h3 : 12 * y + (-4) * z < 0) (_ : prime 7) : False := by omega

example (i n : Nat) (h : (2 : Int) ^ i ≤ 2 ^ n) : (0 : Int) ≤ 2 ^ n - 2 ^ i := by omega

-- Check we use `exfalso` on non-comparison goals.
example (prime : Nat → Prop) (_ b _ : Nat) (h2 : b > 0) (h3 : b < 0) : prime 10 := by
  omega

example (a b c : Nat) (h2 : (2 : Nat) > 3)  : a + b - c ≥ 3 := by omega

-- Verify that we split conjunctions in hypotheses.
example (x y : Int)
    (h : 6 + ((x + 4) * x + (6 + 3 * y) * y) = 3 ∧ (x + 4) * x ≥ 0 ∧ (6 + 3 * y) * y ≥ 0) :
    False := by omega

example (mess : Nat → Nat) (S n : Nat) :
    mess S + (n * mess S + n * 2 + 1) < n * mess S + mess S + (n * 2 + 2) := by omega

example (p n p' n' : Nat) (h : p + n' = p' + n) : n + p' = n' + p := by
  omega

example (a b c : Int) (h1 : 32 / a < b) (h2 : b < c) : 32 / a < c := by omega

-- Check that `autoParam` wrappers do not get in the way of using hypotheses.
example (i n : Nat) (hi : i ≤ n := by omega) : i < n + 1 := by
  omega

-- Test that we consume expression metadata when necessary.
example : 0 = 0 := by
  have : 0 = 0 := by omega
  omega -- This used to fail.

/-! ### `Prod.Lex` -/

-- This example comes from the termination proof
-- for `permutationsAux.rec` in `Mathlib.Data.List.Defs`.
example {x y : Nat} : Prod.Lex (· < ·) (· < ·) (x, x) (Nat.succ y + x, Nat.succ y) := by omega

-- We test the termination proof in-situ:
def List.permutationsAux.rec' {C : List α → List α → Sort v} (H0 : ∀ is, C [] is)
    (H1 : ∀ t ts is, C ts (t :: is) → C is [] → C (t :: ts) is) : ∀ l₁ l₂, C l₁ l₂
  | [], is => H0 is
  | t :: ts, is =>
      H1 t ts is (permutationsAux.rec' H0 H1 ts (t :: is)) (permutationsAux.rec' H0 H1 is [])
  termination_by ts is => (length ts + length is, length ts)
  decreasing_by all_goals simp; omega

example {x y w z : Nat} (h : Prod.Lex (· < ·) (· < ·) (x + 1, y + 1) (w, z)) :
    Prod.Lex (· < ·) (· < ·) (x, y) (w, z) := by omega

-- Verify that we can handle `iff` statements in hypotheses:
example (a b : Int) (h : a < 0 ↔ b < 0) (w : b > 3) : a ≥ 0 := by omega

-- Verify that we can prove `iff` goals:
example (a b : Int) (h : a > 7) (w : b > 2) : a > 0 ↔ b > 0 := by omega

-- Verify that we can prove implications:
example (a : Int) : a > 0 → a > -1 := by omega

-- Verify that we can introduce multiple arguments:
example (x y : Int) : x + 1 ≤ y → ¬ y + 1 ≤ x := by omega

-- Verify that we can handle double negation:
example (x y : Int) (_ : x < y) (_ : ¬ ¬ y < x) : False := by omega

-- Verify that we don't treat function goals as implications.
example (a : Nat) (h : a < 0) : Nat → Nat := by omega

-- Example from Cedar:
example {a₁ a₂ p₁ p₂ : Nat}
  (h₁ : a₁ = a₂ → ¬p₁ = p₂) :
  (a₁ < a₂ ∨ a₁ = a₂ ∧ p₁ < p₂) ∨ a₂ < a₁ ∨ a₂ = a₁ ∧ p₂ < p₁ := by omega

-- From https://github.com/leanprover/std4/issues/562
example {i : Nat} (h1 : i < 330) (_h2 : 7 ∣ (660 + i) * (1319 - i)) : 1319 - i < 1979 := by
  omega

example {a : Int} (_ : a < min a b) : False := by omega (config := { splitMinMax := false })
example {a : Int} (_ : max a b < b) : False := by omega (config := { splitMinMax := false })
example {a : Nat} (_ : a < min a b) : False := by omega (config := { splitMinMax := false })
example {a : Nat} (_ : max a b < b) : False := by omega (config := { splitMinMax := false })

example {a b : Nat} (_ : a = 7) (_ : b = 3) : min a b = 3 := by
  fail_if_success omega (config := { splitMinMax := false })
  omega

example {a b : Nat} (_ : a + b = 9) : (min a b) % 2 + (max a b) % 2 = 1 := by
  fail_if_success omega (config := { splitMinMax := false })
  omega

example {a : Int} (_ : a < if a ≤ b then a else b) : False := by omega
example {a b : Int} : (if a < b then a else b - 1) ≤ b := by omega

-- Check that we use local values.
example (i j : Nat) (p : i ≥ j) : True := by
  let l := j - 1
  have _ : i ≥ l := by omega
  trivial

example (i j : Nat) (p : i ≥ j) : True := by
  let l := j - 1
  let k := l
  have _ : i ≥ k := by omega
  trivial

-- From https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/Nat.2Emul_sub_mod/near/428107094
example (a b : Nat) (h : a % b + 1 = 0) : False := by omega

-- From https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/omega.20regression.20in.204.2E8.2E0-rc1/near/437150155
example (x : Nat) : x < 2 →
    (0 = 0 → 0 = 0 → 0 = 0 → 0 = 0 → x < 2) ∧ (0 = 0 → 0 = 0 → 0 = 0 → 0 = 0 → x < 2 → x < 3) := by
  omega

-- Reported in Lean FRO office hours 2024-05-16 by Michael George
example (s : Int) (s0 : s < (0 : Int)) : 63 + (s - 2 ^ 63) ≤ 62 - 2 ^ 63 := by
  omega

-- From https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/nat.20fighting
example (n : Nat) : n * n ≥ 0 := by omega
example (n : Nat) : n * n + n ≥ 0 := by omega
example (i j k l : Nat) : i * j + k + l - k = i * j + l := by omega

example (n : Nat) : n * 2 = n + n := by omega
example (n : Nat) : n * n * 2 = n * n + n * n := by omega
example (n : Nat) : 2 * (n * n) = n * n + n * n := by omega
-- But not:
-- example (n : Nat) : 2 * n * n = n * n + n * n := by omega
-- example (n : Nat) : n * 2 * n = n * n + n * n := by omega

-- From https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/omega.20regression/near/456539091
example (a : Nat) : a * 1 = a := by omega

/-! ### Fin -/

-- Test `<`
example (n : Nat) (i j : Fin n) (h : i < j) : (i : Nat) < n - 1 := by omega

-- Test `≤`
example (n : Nat) (i j : Fin n) (h : i < j) : (i : Nat) ≤ n - 2 := by omega

-- Test `>`
example (n : Nat) (i j : Fin n) (h : i < j) : n - 1 > i := by omega

-- Test `≥`
example (n : Nat) (i : Fin n) : n - 1 ≥ i := by omega

-- Test `=`
example (n : Nat) (i j : Fin n) (h : i = j) : (i : Int) = j := by omega

example (i j : Fin n) (w : i < j) : i < j := by omega

example (n m i : Nat) (j : Fin (n - m)) (h : i < j) (h2 : m ≥ 4) :
    (i : Int) < n - 5 := by omega

example (x y : Nat) (_ : 2 ≤ x) (_ : x ≤ 3) (_ : 2 ≤ y) (_ : y ≤ 3) :
    4 ≤ (x + y) % 8 ∧ (x + y) % 8 ≤ 6 := by
  omega

example (x y : Fin 8) (_ : 2 ≤ x) (_ : x ≤ 3) (_ : 2 ≤ y) (_ : y ≤ 3) : 4 ≤ x + y ∧ x + y ≤ 6 := by
  omega

example (i : Fin 7) : (i : Nat) < 8 := by omega

/-! ### mod 2^n -/

example (x y z i : Nat) (hz : z ≤ 1) : x % 2 ^ i + y % 2 ^ i + z < 2 * 2^ i := by omega

-- Check that we correctly process base^(e+1) for constant base.
example (x e : Nat) (hx : x < 2^(e+1)) : x < 2^e * 2 := by omega

-- Check that we correctly handle `e.succ`
example (x e : Nat) (hx : x < 2^(e.succ)) : x < 2^e * 2 := by omega

-- Check that this works for integer base.
example (x : Int) (e : Nat) (hx : x < (2 : Int)^(e+1)) : x < 2^e * 2 := by omega

example (n : Nat) (i : Int) (h2n : (2 : Int) ^ n = ↑((2 : Nat) ^ (n : Nat)))
    (hlt : i % 2 ^ n < 2 ^ n) :  2 ^ n ≠ 0 := by
  omega

/-! ### Ground terms -/

example : 2^7 < 165 := by omega
example (_ : x % 2^7 < 3) : x % 128 < 5 := by omega

example (a : Nat) :
    (((a + (2 ^ 64 - 1)) % 2 ^ 64 + 1) * 8 - 1 - (a + (2 ^ 64 - 1)) % 2 ^ 64 * 8 + 1) = 8 := by
  omega

/-! ### BitVec -/
open BitVec

example (x y : BitVec 8) (_ : x < y) : x ≠ y := by
  bv_omega

example (x y : BitVec 8) (hx : x < 16) (hy : y < 16) : x + y < 31 := by
  bv_omega

example (x y z : BitVec 8)
    (hx : x >>> 1 < 16) (hy : y < 16) (hz : z = x + 2 * y) : z ≤ 64 := by
  bv_omega

example (x : BitVec 8) (hx : (x + 1) <<< 1 = 3) : False := by
  bv_omega

example (x : BitVec 8) (hx : (x + 1) <<< 1 = 4) : x = 1 ∨ x = 129 := by
  bv_omega

example (x y : BitVec 64) (_ : x < (y.truncate 32).zeroExtend 64) :
    ~~~x > (1#64 <<< 63) := by
  bv_omega

-- This example, reported from LNSym,
-- started failing when we changed the definition of `Fin.sub` in https://github.com/leanprover/lean4/pull/4421.
-- When we use the new definition, `omega` produces a proof term that the kernel is very slow on.
-- To work around this for now, I've removed `BitVec.toNat_sub` from the `bv_toNat` simp set,
-- and replaced it with `BitVec.toNat_sub'` which uses the old definition for subtraction.
-- This is only a workaround, and I would like to understand why the term chokes the kernel.
example
    (n : Nat)
    (addr2 addr1 : BitVec 64)
    (h0 : n ≤ 18446744073709551616)
    (h1 : addr2 + 18446744073709551615#64 - addr1 ≤ BitVec.ofNat 64 (n - 1))
    (h2 : addr2 - addr1 ≤ addr2 + 18446744073709551615#64 - addr1) :
    n = 18446744073709551616 := by
  bv_omega

-- This smaller example exhibits the same problem.
example
    (n : Nat)
    (addr2 addr1 : BitVec 16)
    (h0 : n ≤ 65536)
    (h1 : addr2 + 65535#16 - addr1 ≤ BitVec.ofNat 16 (n - 1))
    (h2 : addr2 - addr1 ≤ addr2 + 65535#16 - addr1) :
    n = 65536 := by
  bv_omega

-- From https://github.com/leanprover/lean4/issues/5315
-- This used to fail with an unexpected bound variable error.

def simple_foldl (f: β → α → β) (a: Array α) (i: Nat) (b: β): β :=
  if h: i < a.size then
    simple_foldl f a (i+1) (f b a[i])
  else
    b

/--
error: omega could not prove the goal:
No usable constraints found. You may need to unfold definitions so `omega` can see linear arithmetic facts about `Nat` and `Int`, which may also involve multiplication, division, and modular remainder by constants.
-/
#guard_msgs in
theorem simple_fold_monotonic₁ (a: Array α) (f: β → α → β) (i: Nat) {P: α → β → Prop} {x: α}
  (base: P x b)
  (mono: ∀ x x' y, P x y → P x (f y x')): P x (simple_foldl f a i b) := by
    unfold simple_foldl
    split <;> try trivial
    apply simple_fold_monotonic₁
    . apply mono; exact base
    . exact mono
  termination_by a.size - i
  decreasing_by
    exfalso
    rename_i a b
    clear a b mono base
    rename_i a; clear a
    clear base
    clear x
    rename_i a; clear a
    clear x
    clear P
    rename_i a; clear a
    clear P
    clear i
    rename_i a; clear a
    clear i
    clear f
    rename_i a; clear a
    clear f
    clear a
    rename_i a; clear a
    clear a
    clear b
    rename_i a
    omega

/-! ### Error messages -/

/--
error: omega could not prove the goal:
No usable constraints found. You may need to unfold definitions so `omega` can see
linear arithmetic facts about `Nat` and `Int`, which may also involve multiplication,
division, and modular remainder by constants.
-/
#guard_msgs in
example : 0 < 0 := by omega

/--
error: omega could not prove the goal:
a possible counterexample may satisfy the constraints
  a ≥ 0
where
 a := ↑x
-/
#guard_msgs in
example (x : Nat) : x < 0 := by omega

/--
error: omega could not prove the goal:
a possible counterexample may satisfy the constraints
  a ≥ 0
  a - b ≥ 0
where
 a := ↑x
 b := y
-/
#guard_msgs in
example (x : Nat) (y : Int) : x < y := by omega

/--
error: omega could not prove the goal:
a possible counterexample may satisfy the constraints
  b ≤ 0
  6 ≤ a ≤ 9
where
 a := x
 b := y
-/
#guard_msgs in
example (x y : Int) : 5 < x ∧ x < 10 → y > 0 := by omega

/--
error: omega could not prove the goal:
a possible counterexample may satisfy the constraints
  d ≥ 0
  c ≥ 0
  c + d ≥ -1
  b ≥ 0
  a ≥ 0
  a - b ≥ 1
  a - d ≤ -1
where
 a := ↑(sizeOf xs)
 b := ↑(sizeOf y)
 c := ↑(sizeOf x.fst)
 d := ↑(sizeOf x.snd)
-/
#guard_msgs in
-- this used to fail with y = x, but then omega got better, so now there are unrelated x and y
-- to make omega fail
theorem sizeOf_snd_lt_sizeOf_list {α : Type u} {β : Type v} [SizeOf α] [SizeOf β]
  {x y : α × β} {xs : List (α × β)} :
  y ∈ xs → sizeOf x.snd < 1 + sizeOf xs
:= by
  intro h
  have := List.sizeOf_lt_of_mem h
  have : sizeOf x = 1 + sizeOf x.1 + sizeOf x.2 := rfl
  omega


/--
error: omega could not prove the goal:
a possible counterexample may satisfy the constraints
  c ≥ 0
  b ≥ 0
  a ≥ 0
  a - b - c ≥ 0
where
 a := ↑reallyreallyreallyreally
 b := ↑longlonglonglong
 c := ↑namenamename
-/
#guard_msgs in
example (reallyreallyreallyreally longlonglonglong namenamename : Nat) :
  reallyreallyreallyreally < longlonglonglong + namenamename := by omega


def a := 1

/--
error: omega could not prove the goal:
a possible counterexample may satisfy the constraints
  e_1 ≥ 0
  d_1 ≥ 0
  c_1 ≥ 0
  b_1 ≥ 0
  a_1 ≥ 0
  z ≥ 0
  y ≥ 0
  x ≥ 0
  w ≥ 0
  v ≥ 0
  u ≥ 0
  t ≥ 0
  s ≥ 0
  r ≥ 0
  q ≥ 0
  q + r + s + t + u + v + w + x + y + z + a_1 + b_1 + c_1 + d_1 + e_1 ≥ 100
where
 q := ↑b
 r := ↑c
 s := ↑d
 t := ↑e
 u := ↑f
 v := ↑g
 w := ↑h
 x := ↑i
 y := ↑j
 z := ↑k
 a_1 := ↑l
 b_1 := ↑m
 c_1 := ↑n
 d_1 := ↑o
 e_1 := ↑p
-/
#guard_msgs in
example (b c d e f g h i j k l m n o p : Nat) :
  b + c + d + e + f + g + h + i + j + k + l + m + n + o + p < 100 := by omega
