Repository: leanprover/lean4
Pull request #7671: feat: add `BitVec.sdivOverflow` definition and lemmas for overflow in signed and unsigned division
Author: login: luisacicolini
Labels: name: toolchain-available
description: A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN
name: changelog-library
description: Library
Created: 2025-03-24T22:56:26Z | Merged: 2025-04-24T15:52:29Z

This PR contains the theorem proving that signed division x.toInt / y.toInt only overflows when `x = intMin w` and `y = allOnes w` (for `0 < w`).
To show that this is the *only* case in which overflow happens, we refer to overflow for negation (`BitVec.sdivOverflow_eq_negOverflow_of_neg_one`): in fact, `x.toInt/(allOnes w).toInt = - x.toInt`, i.e., the overflow conditions are the same as `negOverflow` for `x`, and then reason about the signs of the operands with the respective theorems. 
These BitVec theorems themselves rely on numerous `Int.ediv_*` theorems, that carefully set the bounds of signed division for integers.

co-authored by @bollu, @tobiasgrosser 


Diff:
diff --git a/src/Init/Data/BitVec/Basic.lean b/src/Init/Data/BitVec/Basic.lean
index c8f5216274db..25c5c264045f 100644
--- a/src/Init/Data/BitVec/Basic.lean
+++ b/src/Init/Data/BitVec/Basic.lean
@@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
+
+SMT-LIB name: `bvsdivo`.
+-/
+def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
+  (2 ^ (w - 1) ≤ x.toInt / y.toInt) || (x.toInt / y.toInt <  - 2 ^ (w - 1))
+
 /- ### reverse -/
 
 /-- Reverses the bits in a bitvector. -/
diff --git a/src/Init/Data/BitVec/Bitblast.lean b/src/Init/Data/BitVec/Bitblast.lean
index 7c887c2a9ffe..573ba4f2f511 100644
--- a/src/Init/Data/BitVec/Bitblast.lean
+++ b/src/Init/Data/BitVec/Bitblast.lean
@@ -1359,6 +1359,38 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division `x.toInt / y.toInt` only overflows when `x = intMin w` and `y = allOnes w` (for `0 < w`).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y)
+    have ylt := two_mul_toInt_lt (x := y)
+    -- if y = allOnes (w + 1), thus y.toInt = -1,
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y)
+      simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+      · by_cases hy' : 0 ≤ y.toInt
+        · have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+        · have := BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one
+                (x := x) (y := y) (by omega) (by rw [← toInt_inj, toInt_allOnes] at hy; omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+
 theorem umulOverflow_eq {w : Nat} (x y : BitVec w) :
     umulOverflow x y =
       (0 < w && BitVec.twoPow (w * 2) w ≤ x.zeroExtend (w * 2) * y.zeroExtend (w * 2)) := by
diff --git a/src/Init/Data/BitVec/Lemmas.lean b/src/Init/Data/BitVec/Lemmas.lean
index c383a2bee3ad..549ed04e88b6 100644
--- a/src/Init/Data/BitVec/Lemmas.lean
+++ b/src/Init/Data/BitVec/Lemmas.lean
@@ -4148,6 +4148,110 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp only [hx', Int.zero_ediv, Nat.add_one_sub_one, gt_iff_lt]
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denominator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonpos. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers `x` and `y`: `x/y = q ↔ x.ediv y = q ↔ r = x.emod y`
+  and in particular: `-1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y`.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} :
+    (-1) / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · cases eq_zero_or_eq_one y
+    · case _ h => simp [h]
+    · case _ h => simp [h]
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denominator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < -1) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.neg_one_ediv_toInt_eq (y := y)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+/-- Signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt. -/
+theorem neg_two_pow_le_toInt_ediv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
+  have xlt := @toInt_lt w x; have lex := @le_toInt w x
+  by_cases hx : 0 ≤ x.toInt <;> by_cases hy : 0 ≤ y.toInt
+  · have := Int.ediv_nonneg_of_nonneg_of_nonneg (x := x.toInt) (y := y.toInt) hx hy
+    omega
+  · have := Int.neg_self_le_ediv_of_nonneg_of_nonpos (x := x.toInt) (y := y.toInt) hx (by omega)
+    omega
+  · have := Int.self_le_ediv_of_nonpos_of_nonneg (x := x.toInt) (y := y.toInt) (by omega) hy
+    omega
+  · have := Int.ediv_nonneg_of_nonpos_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+    omega
+
 /-! ### smtSDiv -/
 
 theorem smtSDiv_eq (x y : BitVec w) : smtSDiv x y =
@@ -5145,6 +5249,22 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = -x.toInt := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp [toInt_allOnes]
+
+theorem sdivOverflow_eq_negOverflow_of_eq_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
+    sdivOverflow x y = negOverflow x := by
+  rcases w with _|w
+  · simp [sdivOverflow, negOverflow, of_length_zero]
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp only [sdivOverflow, hy, show ¬2 ^ w < x.toInt by omega, negOverflow]
+    by_cases hx : x.toInt = - 2 ^ w
+    · simp [hx]
+    · simp [show ¬x.toInt == -2 ^ w by simp only [beq_iff_eq, hx, not_false_eq_true]]; omega
+
 theorem two_pow_le_toInt_mul_toInt_iff {x y : BitVec w} :
     2 ^ (w - 1) ≤ x.toInt * y.toInt ↔
       (signExtend (w * 2) (intMax w)).slt (signExtend (w * 2) x * signExtend (w * 2) y) := by
diff --git a/src/Init/Data/Int/DivMod/Lemmas.lean b/src/Init/Data/Int/DivMod/Lemmas.lean
index 5b780239fe7b..bd04548eebf2 100644
--- a/src/Init/Data/Int/DivMod/Lemmas.lean
+++ b/src/Init/Data/Int/DivMod/Lemmas.lean
@@ -2894,6 +2894,65 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · obtain ⟨xn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    rw [← Int.ofNat_ediv]
+    norm_cast
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  obtain ⟨xn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  rw [← Int.ofNat_ediv]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/--  When both x and y are negative we need stricter bounds on x and y
+  to establish the upper bound of x/y, i.e., x / y < x.natAbs.
+  In particular, consider the following counter examples:
+  · (-1) / (-2) = 1 and ¬ 1 < (-1).natAbs
+    (note that Int.neg_one_ediv already handles `ediv` where the numerator is -1)
+  · (-2) / (-1) = 2 and ¬ 1 < (-2).natAbs
+  To exclude these cases, we enforce stricter bounds on the values of x and y.
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one {x y : Int} (hx : x < -1) (hy : y < -1) :
+    x / y < x.natAbs := by
+  obtain ⟨xn, rfl⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, rfl⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [negSucc_ediv_negSucc, Int.natCast_add, natCast_ediv, cast_ofNat_Int, natAbs_negSucc,
+    Nat.succ_eq_add_one, Int.add_lt_add_iff_right]
+  rw_mod_cast [Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_nonpos_of_nonneg {x y : Int} (hx : x ≤ 0) (hy : 0 ≤ y) :
+    x ≤ x / y := by
+  by_cases hx' : x = 0
+  · simp [hx', zero_ediv]
+  · by_cases hy : y = 0
+    · simp [hy]; omega
+    · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+        show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+      apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx : 0 ≤ x) (hy : y ≤ 0) :
+    -x ≤ x / y := by
+  by_cases hy' : y = 0
+  · simp [hy']; omega
+  · obtain ⟨xn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, rfl⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+    rw [show xn = ofNat xn by norm_cast, Int.ofNat_ediv_negSucc (a := xn)]
+    simp only [ofNat_eq_coe, natCast_ediv, Int.natCast_add, cast_ofNat_Int, Int.neg_le_neg_iff]
+    norm_cast
+    apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
+
 /-! Helper theorems for `dvd` simproc -/
 
 protected theorem dvd_eq_true_of_mod_eq_zero {a b : Int} (h : b % a == 0) : (a ∣ b) = True := by
diff --git a/src/Std/Tactic/BVDecide/Normalize/BitVec.lean b/src/Std/Tactic/BVDecide/Normalize/BitVec.lean
index b3b0d1a39a8e..1ece37d0ed87 100644
--- a/src/Std/Tactic/BVDecide/Normalize/BitVec.lean
+++ b/src/Std/Tactic/BVDecide/Normalize/BitVec.lean
@@ -362,6 +362,7 @@ attribute [bv_normalize] BitVec.umulOverflow_eq
 attribute [bv_normalize] BitVec.smulOverflow_eq
 attribute [bv_normalize] BitVec.usubOverflow_eq
 attribute [bv_normalize] BitVec.ssubOverflow_eq
+attribute [bv_normalize] BitVec.sdivOverflow_eq
 
 /-- `x / (BitVec.ofNat n)` where `n = 2^k` is the same as shifting `x` right by `k`. -/
 theorem BitVec.udiv_ofNat_eq_of_lt (w : Nat) (x : BitVec w) (n : Nat) (k : Nat) (hk : 2 ^ k = n) (hlt : k < w) :
diff --git a/tests/lean/run/bv_decide_rewriter.lean b/tests/lean/run/bv_decide_rewriter.lean
index 851a966c54a7..f40fcc653aea 100644
--- a/tests/lean/run/bv_decide_rewriter.lean
+++ b/tests/lean/run/bv_decide_rewriter.lean
@@ -647,6 +647,8 @@ example {x y : BitVec 64} : ((x = 0#64) ∧ (y = BitVec.allOnes 64)) → (BitVec
 
 example {x y : BitVec 64} : ((x = BitVec.twoPow 64 62) ∧ (y = BitVec.twoPow 64 63)) → (BitVec.ssubOverflow x y) := by bv_decide
 
+example {x y : BitVec 64} : ((x = BitVec.intMin 64) ∧ (y = BitVec.allOnes 64)) ↔ (BitVec.sdivOverflow x y) := by bv_decide
+
 -- BV_EXTRACT_ADD_MUL
 example {x y : BitVec 8} :
     BitVec.extractLsb' 0 4 (x + y) = BitVec.extractLsb' 0 4 x + BitVec.extractLsb' 0 4 y := by


Reviews:
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T22:57:06Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T05:49:46Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T14:37:30Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T14:56:24Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T15:05:20Z
user: login: bollu
body: I believe in `Int`, the theorems are called as `div_...` rather than `sdiv_...`? So I'd at the very least change that. We also have theorems that use `ge`, which is not the `simp` normal form:

- `sdiv_neg_ge_two_ge`
- `sdiv_neg_le_neg_two_ge`

state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-01T15:40:37Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-05T08:20:47Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-05T12:39:15Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T06:46:58Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T06:48:53Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T06:51:21Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T07:02:45Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T07:20:18Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T07:31:46Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:46:19Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:47:38Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:47:52Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:49:04Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:49:15Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:49:38Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:50:00Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T08:55:57Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:06:49Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:07:37Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:07:50Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:08:01Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:08:16Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:08:23Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:08:31Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:08:42Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:08:55Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:09:14Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:09:20Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:09:27Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:09:56Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:12:21Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T19:16:20Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:22:36Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:23:59Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:25:54Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:28:09Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:29:41Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:31:31Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:39:41Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-06T22:40:32Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T05:59:58Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:00:10Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:00:30Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:00:42Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:00:53Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:01:53Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:02:28Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:03:09Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T06:47:37Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T07:06:30Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:15:55Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:23:10Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:24:39Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:28:36Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:29:57Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:30:02Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:36:20Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:37:19Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:37:32Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:37:48Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:38:10Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:40:14Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:41:56Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:45:10Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:45:49Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:46:58Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:46:59Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:47:49Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:48:27Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:49:26Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:50:12Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-07T20:50:24Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T04:43:23Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T05:02:37Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T20:57:49Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T15:31:19Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T15:41:01Z
user: login: bollu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T16:24:29Z
user: login: bollu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T16:29:03Z
user: login: bollu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T16:32:32Z
user: login: bollu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T16:35:19Z
user: login: bollu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T16:37:20Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T16:43:30Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T16:52:42Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T18:45:38Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T18:45:49Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T18:56:36Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T19:02:01Z
user: login: bollu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-13T23:07:45Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-14T07:06:56Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-15T07:59:47Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:03:59Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:07:16Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:13:23Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:18:09Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:18:36Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:20:53Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:21:31Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:21:38Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:21:46Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:21:57Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:22:11Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T07:24:22Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T09:46:33Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T09:46:56Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T09:47:31Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T12:00:48Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T12:04:32Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-18T12:59:27Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T18:05:19Z
user: login: tobiasgrosser
body: Another run of naming comments. I hope this is the last one.
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T18:16:58Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T21:35:13Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T21:40:37Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T21:40:43Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T21:40:51Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-20T21:40:56Z
user: login: bollu
body: We're getting there, the proofs look clean :) I have some simp-normal-form questions, and two naming convention changes, for which I'll request changes before a final round of review. 
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:25:03Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:34:37Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:35:08Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:39:50Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:41:13Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:42:12Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:42:46Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T17:51:28Z
user: login: bollu
body: LGTM, thanks for the heroic work :) This was definitely a long one, since we had to build tons of theory. I've added naming convention nits that I believe should be merged, but other than that, the proofs look good to go from my side.

state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T21:30:25Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T21:37:16Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T21:38:17Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T21:39:36Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-21T21:48:57Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T05:50:12Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T05:51:18Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T07:30:08Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T07:30:30Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T07:51:16Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:01:03Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:02:13Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:08:07Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:38:20Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:38:51Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:39:01Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:40:55Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:41:23Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:45:41Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:46:05Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:46:50Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:48:13Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:49:32Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:51:43Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T08:51:48Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:11:00Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:13:34Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:14:00Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:14:21Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:14:50Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:15:25Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:15:33Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:15:38Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:18:19Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:21:30Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:21:57Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:22:09Z
user: login: tobiasgrosser
body: I think this is good to go. Thank you, @luisacicolini for all your effort.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:23:45Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:24:43Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:24:52Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:25:51Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:26:01Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:29:40Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:29:52Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:30:54Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T09:31:03Z
user: login: hargoniX
body: Looks generally fine :+1:, `Int` stuff someone else should probably do as per usual.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T10:00:42Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:07:05Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:08:29Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:08:42Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:09:19Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:09:50Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:09:59Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:10:19Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:10:52Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:11:27Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:13:24Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:16:55Z
user: login: tobiasgrosser
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T14:56:00Z
user: login: luisacicolini
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-22T15:26:52Z
user: login: TwoFX
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-23T15:27:47Z
user: login: TwoFX
body: `Int` lemmas look good to me, thanks!
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-04-24T13:54:37Z

Review comments:
diff_hunk: @@ -512,6 +512,7 @@ protected theorem sub_mul (a b c : Int) : (a - b) * c = a * c - b * c := by
   | ofNat n => show ofNat (1 * n) = ofNat n by rw [Nat.one_mul]
   | -[n+1]  => show -[1 * n +1] = -[n+1] by rw [Nat.one_mul]
 
+
path: src/Init/Data/Int/Lemmas.lean
user: login: luisacicolini
body: ```suggestion

```
created_at: 2025-03-24T22:57:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -704,14 +704,23 @@ treating `x` and `y` as 2's complement signed bitvectors.
 def ssubOverflow {w : Nat} (x y : BitVec w) : Bool :=
   (x.toInt - y.toInt ≥ 2 ^ (w - 1)) || (x.toInt - y.toInt < - 2 ^ (w - 1))
 
-/-- `negOverflow x` returns `true` if the negation of `x` results in overflow. 
-For a BitVec `x` with width `0 < w`, this only happens if `x = intMin`. 
+/-- `negOverflow x` returns `true` if the negation of `x` results in overflow.
+For a BitVec `x` with width `0 < w`, this only happens if `x = intMin`.
 
   SMT-Lib name: `bvnego`.
 -/
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+negOverflow x` returns `true` if the divisioin of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with width `0 < w`, this only happens if `x = intMin` and `y = allOnes w`.
path: src/Init/Data/BitVec/Basic.lean
user: login: tobiasgrosser
body: ```suggestion
negOverflow x` returns `true` if the division of `x` by `y` results in overflow.
For BitVecs `x` and `y` with width `0 < w`, this only happens if `x = intMin` and `y = allOnes w`.
```
created_at: 2025-03-25T05:49:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1329,6 +1329,245 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+theorem Int.le_of_nonpos_of_pos {x : Int} (hx : x ≤ 0) {y : Int} (hy : 0 < y) : x * y ≤ x := by
+  conv => rhs; rw [← Int.mul_one x] -- this is crazy lazy, find the theorem...
+  apply Int.mul_le_mul_of_nonpos_left <;> omega
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: What is this comment about?
created_at: 2025-03-25T14:37:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -704,14 +704,23 @@ treating `x` and `y` as 2's complement signed bitvectors.
 def ssubOverflow {w : Nat} (x y : BitVec w) : Bool :=
   (x.toInt - y.toInt ≥ 2 ^ (w - 1)) || (x.toInt - y.toInt < - 2 ^ (w - 1))
 
-/-- `negOverflow x` returns `true` if the negation of `x` results in overflow. 
-For a BitVec `x` with width `0 < w`, this only happens if `x = intMin`. 
+/-- `negOverflow x` returns `true` if the negation of `x` results in overflow.
+For a BitVec `x` with width `0 < w`, this only happens if `x = intMin`.
path: src/Init/Data/BitVec/Basic.lean
user: login: luisacicolini
body: ```suggestion
/-- `negOverflow x` returns `true` if the negation of `x` results in overflow. 
For a BitVec `x` with width `0 < w`, this only happens if `x = intMin`. 
```
created_at: 2025-04-01T14:56:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2339,4 +2410,5 @@ protected theorem dvd_eq_false_of_mod_ne_zero {a b : Int} (h : b % a != 0) : (a
   simp [eq_of_beq] at h
   simp [Int.dvd_iff_emod_eq_zero, h]
 
+
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: ```suggestion

```
created_at: 2025-04-01T15:05:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2330,6 +2330,77 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### sdiv, ediv -/
+
+theorem sdiv_pos_ge_two_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+theorem sdiv_pos_ge_two_ge (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+theorem sdiv_lt_neg_one_le_neg_two_lt (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem sdiv_neg_le_neg_two_ge (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem sdiv_neg_ge_two_ge (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem div_le_of_two_le_of_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
```

I wonder what the canonical way of spelling `x < 0` is in the theorem name: do we say `lt_zero`?
created_at: 2025-04-01T15:38:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2330,6 +2330,77 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### sdiv, ediv -/
+
+theorem sdiv_pos_ge_two_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+theorem sdiv_pos_ge_two_ge (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+theorem sdiv_lt_neg_one_le_neg_two_lt (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem sdiv_neg_le_neg_two_ge (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem sdiv_neg_ge_two_ge (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y ≥ x := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem sdiv_neg_ge_two_lt (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y < 0 := by
+  refine Int.ediv_neg_of_neg_of_pos hx' ?_
+  omega
+
+theorem sdiv_pos_le_neg_two_ge (x y : Int) (hy' : y ≤ -2) (hx' : 0 < x) :
+    x / y ≥ -x := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
+
+theorem sdiv_pos_le_neg_two_le (x y : Int) (hy' : y ≤ -2) (hx' : 0 < x) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem sdiv_nonpos_of_le_neg_two_of_zero_lt (x y : Int) (hy' : y ≤ -2) (hx' : 0 < x) :
```

It would be good to have an English sentence that explains what's going on. Also, doesn't the theorem hold for a looser bound, when `y <= -1`? We should try to now generalize our statements, as the proof goes through.
created_at: 2025-04-01T15:39:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem udiv_lt_self_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
    x / y < x := by
```
created_at: 2025-04-05T08:20:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem zero_le_ediv_of_two_le_of_zero_lt (x y : Int) (hy' : 0 < y) (hx' : 0 < x):
    0 ≤ x / y := by
```

the same below

Also, `hy'` can be weakened to `0 < y`.

I would expect you can even prove:

```lean
theorem ediv_nonneg_of_nonneg_of_nonneg (x y : Int) (hy' : 0 ≤ y) (hx' : 0 ≤ x):
    0 ≤ x / y := by
```

In general, I would prefer `nonneg, nonpos, pos, neg` as names for the conditions, if applicable.
created_at: 2025-04-05T12:39:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: Is this comment still true? All proofs seem to go through?
created_at: 2025-04-06T06:46:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: What is `udiv`? Can you double-check that Int has an `udiv` operation. I feel what you are referring to is `\` which is called `ediv`. Please double-check this and do a pass over this PR based on what you find out.
created_at: 2025-04-06T06:48:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,84 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is positive
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : 0 < x.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · have := Int.ediv_lt_self_of_two_le_of_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.zero_le_udiv_of_two_le_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem neg_two_pow_le_sdiv_and_sdiv_lt_zero_of_two_le_of_neg {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : x.toInt < 0) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have := Int.udiv_lt_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.self_le_udiv_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem neg_two_pow_le_sdiv_and_sdiv_le_zero_of_le_neg_two_of_pos {w : Nat} {x y : BitVec w} (hy : y.toInt ≤ -2) (hx : 0 < x.toInt) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.udiv_le_of_le_neg_two_lt_zero (x := x.toInt) (y := y.toInt) (by omega) hx
+      have := Int.neg_self_le_udiv_of_le_neg_two_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+      simp; omega
+
+theorem toInt_sdiv_of_one {x y : BitVec 1} :
+    x.toInt / y.toInt = x &&& y := by
+  have hx := eq_zero_or_eq_one (a := x)
+  have hy := eq_zero_or_eq_one (a := y)
+  rcases hx with hx|hx <;> rcases hy with hy|hy
+  <;> (simp [hx, hy]; norm_cast)
+
+theorem sdiv_eq_of_neg_one {w : Nat} {y : BitVec w} (hy : ¬ y.toInt = 0) (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if 0 < y.toInt then (allOnes w).toInt else (1#w).toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hy : y.toInt ≠  0) (hw : 1 < w) :
    (allOnes w).toInt / y.toInt = if 0 < y.toInt then -1 else 1 := by
```

I think you can inline the resulting values. Also, why do you require y.toInt = 0. I would just add an additional if `y = 0` on the RHS which yields `0`.
created_at: 2025-04-06T06:51:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,84 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is positive
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : 0 < x.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · have := Int.ediv_lt_self_of_two_le_of_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.zero_le_udiv_of_two_le_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem neg_two_pow_le_sdiv_and_sdiv_lt_zero_of_two_le_of_neg {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : x.toInt < 0) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have := Int.udiv_lt_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.self_le_udiv_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem neg_two_pow_le_sdiv_and_sdiv_le_zero_of_le_neg_two_of_pos {w : Nat} {x y : BitVec w} (hy : y.toInt ≤ -2) (hx : 0 < x.toInt) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.udiv_le_of_le_neg_two_lt_zero (x := x.toInt) (y := y.toInt) (by omega) hx
+      have := Int.neg_self_le_udiv_of_le_neg_two_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+      simp; omega
+
+theorem toInt_sdiv_of_one {x y : BitVec 1} :
+    x.toInt / y.toInt = x &&& y := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: There already exists `sdiv_eq_and`. Does this theorem add something or can we use `sdiv_eq_and`?
created_at: 2025-04-06T07:02:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -362,6 +362,7 @@ attribute [bv_normalize] BitVec.umulOverflow_eq
 attribute [bv_normalize] BitVec.smulOverflow_eq
 attribute [bv_normalize] BitVec.usubOverflow_eq
 attribute [bv_normalize] BitVec.ssubOverflow_eq
+attribute [bv_normalize] BitVec.sdivOverflow_eq
path: src/Std/Tactic/BVDecide/Normalize/BitVec.lean
user: login: tobiasgrosser
body: Do we lack some test cases for bv_normalize?
created_at: 2025-04-06T07:20:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,83 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  Then, we need to show that in all other cases (¬ y.toInt = -1) no overflow happens.
+  To do so, we first exclude special cases:
+  · y.toInt = 0 → x.toInt / y.toInt = 0
+  · y.toInt = 1 → x.toInt / y.toInt = x.toInt
+  · x.toInt = 0 → x.toInt / y.toInt = 0
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos when 2 ≤ y.toInt and 0 < x.toInt
+  · BitVec.neg_two_pow_le_sdiv_and_sdiv_lt_zero_of_two_le_of_neg when 2 ≤ y.toInt and x.toInt < 0
+  · BitVec.neg_two_pow_le_sdiv_and_sdiv_le_zero_of_le_neg_two_of_pos when y.toInt ≤ -2 and 0 < x.toInt
+  · BitVec.zero_le_sdiv_and_sdiv_lt_two_pow_of_le_neg_two_of_neg when y.toInt ≤ -2 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  set the bounds of signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · simp only [Nat.add_one_sub_one, ge_iff_le, zero_lt_succ, decide_true, Bool.true_and]
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    simp only [bool_to_prop]
+    by_cases hy : y = allOnes (w + 1)
+    · -- if y = allOnes (w + 1) the division overflows iff x = intMin (w + 1), as for negation
+      rw [BitVec.sdivOverflow_eq_negOverflow_of_allOnes (x := x) (y := y) hy, negOverflow,
+        Nat.add_one_sub_one, decide_and]
+      simp only [beq_eq_decide_eq, ← toInt_inj, toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod,
+        hy, decide_true, Bool.and_true, decide_eq_decide]
+      norm_cast
+      rw [Nat.mod_eq_of_lt (by apply Nat.pow_lt_pow_of_lt (a := 2) (n := w) (m := w + 1) (by omega) (by omega))]
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
    · -- if y = allOnes (w + 1) the division overflows iff x = intMin (w + 1), as for negation
      simp [sdivOverflow_eq_negOverflow_of_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
```

There is no need to fall to the `toInt` level. You can prove this purely at the `BitVec` level.

created_at: 2025-04-06T07:31:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 1 < y) (hx' : 0 < x):
    x / y < x := by
```

I prefer `1 < y` over `2 <= y`.
created_at: 2025-04-06T08:46:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y < -1) (hx' : x < -1) :
    x / y < x.natAbs := by
```

I prefer `<` over `<=`, also mirroring `hx'`.

created_at: 2025-04-06T08:47:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y < -1) (hx' : x < 0) :
    0 ≤ x / y := by
```
created_at: 2025-04-06T08:47:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 0 < y) (hx' : x < 0) :
    x ≤ x / y := by
```
created_at: 2025-04-06T08:49:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem udiv_lt_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y < 0 := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem udiv_lt_of_two_le_lt_zero (x y : Int) (hy' : 2 < y) (hx' : x < 0) :
    x / y < 0 := by
```
created_at: 2025-04-06T08:49:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem udiv_lt_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y < 0 := by
+  refine Int.ediv_neg_of_neg_of_pos hx' ?_
+  omega
+
+theorem neg_self_le_udiv_of_le_neg_two_zero_lt (x y : Int) (hy' : y ≤ -2) (hx' : 0 < x) :
+    - x ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem neg_self_le_udiv_of_le_neg_two_zero_lt (x y : Int) (hy' : y < 0) (hx' : 0 < x) :
    - x ≤ x / y := by
```
created_at: 2025-04-06T08:49:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem udiv_lt_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y < 0 := by
+  refine Int.ediv_neg_of_neg_of_pos hx' ?_
+  omega
+
+theorem neg_self_le_udiv_of_le_neg_two_zero_lt (x y : Int) (hy' : y ≤ -2) (hx' : 0 < x) :
+    - x ≤ x / y := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
+
+theorem udiv_le_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -1) (hx' : 0 < x) :
+    x / y ≤ 0  := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem udiv_le_of_le_neg_two_lt_zero (x y : Int) (hy' : y < 0) (hx' : 0 < x) :
    x / y ≤ 0  := by
```
created_at: 2025-04-06T08:50:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,84 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is positive
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : 0 < x.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos {w : Nat} {x y : BitVec w} (hy : 1 < y.toInt) (hx : 0 < x.toInt) :
    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
```

I suggest to go over all conditions and see if these are the weakest you can do. Also, prefer `<` over `<=` if possible, as it leads to more canonical constants and often allows us to use `pos`, `neg`, `nonneg`, `nonpos` as more descriptive names.
created_at: 2025-04-06T08:55:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done! all nomes should be consistent with this now, and I tried to relax hypotheses as much as possible
created_at: 2025-04-06T19:06:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: it is - I updated it to clarify why the hypotheses are needed
created_at: 2025-04-06T19:07:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done, it is indeed `ediv` the one I had in mind
created_at: 2025-04-06T19:07:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,84 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is positive
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : 0 < x.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · have := Int.ediv_lt_self_of_two_le_of_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.zero_le_udiv_of_two_le_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem neg_two_pow_le_sdiv_and_sdiv_lt_zero_of_two_le_of_neg {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : x.toInt < 0) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have := Int.udiv_lt_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.self_le_udiv_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem neg_two_pow_le_sdiv_and_sdiv_le_zero_of_le_neg_two_of_pos {w : Nat} {x y : BitVec w} (hy : y.toInt ≤ -2) (hx : 0 < x.toInt) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.udiv_le_of_le_neg_two_lt_zero (x := x.toInt) (y := y.toInt) (by omega) hx
+      have := Int.neg_self_le_udiv_of_le_neg_two_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+      simp; omega
+
+theorem toInt_sdiv_of_one {x y : BitVec 1} :
+    x.toInt / y.toInt = x &&& y := by
+  have hx := eq_zero_or_eq_one (a := x)
+  have hy := eq_zero_or_eq_one (a := y)
+  rcases hx with hx|hx <;> rcases hy with hy|hy
+  <;> (simp [hx, hy]; norm_cast)
+
+theorem sdiv_eq_of_neg_one {w : Nat} {y : BitVec w} (hy : ¬ y.toInt = 0) (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if 0 < y.toInt then (allOnes w).toInt else (1#w).toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-06T19:08:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,84 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is positive
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : 0 < x.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · have := Int.ediv_lt_self_of_two_le_of_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.zero_le_udiv_of_two_le_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem neg_two_pow_le_sdiv_and_sdiv_lt_zero_of_two_le_of_neg {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : x.toInt < 0) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have := Int.udiv_lt_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have := Int.self_le_udiv_of_two_le_lt_zero (x := x.toInt) (y := y.toInt) hy hx
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem neg_two_pow_le_sdiv_and_sdiv_le_zero_of_le_neg_two_of_pos {w : Nat} {x y : BitVec w} (hy : y.toInt ≤ -2) (hx : 0 < x.toInt) (hw : 0 < w) :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [hw]; omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.udiv_le_of_le_neg_two_lt_zero (x := x.toInt) (y := y.toInt) (by omega) hx
+      have := Int.neg_self_le_udiv_of_le_neg_two_zero_lt (x := x.toInt) (y := y.toInt) hy hx
+      simp; omega
+
+theorem toInt_sdiv_of_one {x y : BitVec 1} :
+    x.toInt / y.toInt = x &&& y := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: indeed, the theorem is not necessary so I removed it
created_at: 2025-04-06T19:08:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,83 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  Then, we need to show that in all other cases (¬ y.toInt = -1) no overflow happens.
+  To do so, we first exclude special cases:
+  · y.toInt = 0 → x.toInt / y.toInt = 0
+  · y.toInt = 1 → x.toInt / y.toInt = x.toInt
+  · x.toInt = 0 → x.toInt / y.toInt = 0
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos when 2 ≤ y.toInt and 0 < x.toInt
+  · BitVec.neg_two_pow_le_sdiv_and_sdiv_lt_zero_of_two_le_of_neg when 2 ≤ y.toInt and x.toInt < 0
+  · BitVec.neg_two_pow_le_sdiv_and_sdiv_le_zero_of_le_neg_two_of_pos when y.toInt ≤ -2 and 0 < x.toInt
+  · BitVec.zero_le_sdiv_and_sdiv_lt_two_pow_of_le_neg_two_of_neg when y.toInt ≤ -2 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  set the bounds of signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · simp only [Nat.add_one_sub_one, ge_iff_le, zero_lt_succ, decide_true, Bool.true_and]
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    simp only [bool_to_prop]
+    by_cases hy : y = allOnes (w + 1)
+    · -- if y = allOnes (w + 1) the division overflows iff x = intMin (w + 1), as for negation
+      rw [BitVec.sdivOverflow_eq_negOverflow_of_allOnes (x := x) (y := y) hy, negOverflow,
+        Nat.add_one_sub_one, decide_and]
+      simp only [beq_eq_decide_eq, ← toInt_inj, toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod,
+        hy, decide_true, Bool.and_true, decide_eq_decide]
+      norm_cast
+      rw [Nat.mod_eq_of_lt (by apply Nat.pow_lt_pow_of_lt (a := 2) (n := w) (m := w + 1) (by omega) (by omega))]
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: done!
created_at: 2025-04-06T19:08:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done 
created_at: 2025-04-06T19:08:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-06T19:08:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem udiv_lt_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y < 0 := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done with `< 1`
created_at: 2025-04-06T19:08:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-06T19:09:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem udiv_lt_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y < 0 := by
+  refine Int.ediv_neg_of_neg_of_pos hx' ?_
+  omega
+
+theorem neg_self_le_udiv_of_le_neg_two_zero_lt (x y : Int) (hy' : y ≤ -2) (hx' : 0 < x) :
+    - x ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-06T19:09:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem zero_le_udiv_of_two_le_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1
+-/
+theorem udiv_lt_natAbs_self_of_le_neg_two_lt_neg_one (x y : Int) (hy' : y ≤ -2) (hx' : x < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem zero_le_udiv_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -2) (hx' : x < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_udiv_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem udiv_lt_of_two_le_lt_zero (x y : Int) (hy' : 2 ≤ y) (hx' : x < 0) :
+    x / y < 0 := by
+  refine Int.ediv_neg_of_neg_of_pos hx' ?_
+  omega
+
+theorem neg_self_le_udiv_of_le_neg_two_zero_lt (x y : Int) (hy' : y ≤ -2) (hx' : 0 < x) :
+    - x ≤ x / y := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
+
+theorem udiv_le_of_le_neg_two_lt_zero (x y : Int) (hy' : y ≤ -1) (hx' : 0 < x) :
+    x / y ≤ 0  := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-06T19:09:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,84 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is positive
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_two_le_of_pos {w : Nat} {x y : BitVec w} (hy : 2 ≤ y.toInt) (hx : 0 < x.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I went over all theorems and this should now be fixed with conditions as weak as possible
created_at: 2025-04-06T19:09:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,81 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### udiv, ediv -/
+
+theorem ediv_lt_self_of_two_le_of_zero_lt (x y : Int) (hy' : 2 ≤ y) (hx' : 0 < x):
+    x / y < x := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: fixed everywhere
created_at: 2025-04-06T19:12:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -362,6 +362,7 @@ attribute [bv_normalize] BitVec.umulOverflow_eq
 attribute [bv_normalize] BitVec.smulOverflow_eq
 attribute [bv_normalize] BitVec.usubOverflow_eq
 attribute [bv_normalize] BitVec.ssubOverflow_eq
+attribute [bv_normalize] BitVec.sdivOverflow_eq
path: src/Std/Tactic/BVDecide/Normalize/BitVec.lean
user: login: luisacicolini
body: added one!
created_at: 2025-04-06T19:16:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem ediv_lt_self_of_pos_of_ne_one (x y : Int) (hx' : 0 < x) (hy : y ≠ 1) :
    x / y < x := by
  by_cases hy' : 1 < y
  · rw [Int.div_def]
    unfold Int.ediv
    obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
    obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
    simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
    apply Nat.div_lt_self (by omega) (by omega)
  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
    omega
```

You can generalize this to the above.
created_at: 2025-04-06T22:22:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem ediv_nonneg_of_nonneg_of_nonneg (x y : Int) (hx' : 0 ≤ x) (hy' : 0 ≤ y) :
    0 ≤ x / y := by
  rw [Int.div_def]
  unfold Int.ediv
  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
  exact Int.ofNat_zero_le (xn / yn)
```

If you look higher up in the file, the naming convention is `ediv_nonneg` instead of `nonneg_ediv`. Also, you can weaken `hx'`.
created_at: 2025-04-06T22:23:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: This already exists in a more general variant as `ediv_nonneg_of_nonpos_of_nonpos`.
created_at: 2025-04-06T22:25:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x < 0) (hy' : 0 < y) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem self_le_ediv_of_neg_of_nonneg (x y : Int) (hx' : x < 0) (hy' : 0 ≤ y) :
    x ≤ x / y := by
  by_cases y0 : y = 0
  · subst y0; simp; omega
  · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
      show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
    apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
```

You can weaken here `hy'`.
created_at: 2025-04-06T22:28:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x < 0) (hy' : 0 < y) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_pos_of_neg (x y : Int) (hx' : 0 < x) (hy' : y < 0) :
+    - x ≤ x / y := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem neg_self_le_ediv_of_pos_of_nonpos (x y : Int) (hx' : 0 < x) (hy' : y ≤ 0) :
    - x ≤ x / y := by
  by_cases y0 : y = 0
  · subst y0; simp; omega
  · obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
    obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
    rw [Int.div_def]
    unfold Int.ediv
    simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
    apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
```

You can weaken here `hy'`.
created_at: 2025-04-06T22:29:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x < 0) (hy' : 0 < y) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_pos_of_neg (x y : Int) (hx' : 0 < x) (hy' : y < 0) :
+    - x ≤ x / y := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
+
+theorem nonpos_ediv_of_pos_of_neg (x y : Int) (hx' : 0 < x) (hy' : y < 0) :
+    x / y ≤ 0  := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: This already exists as `ediv_nonpos_of_nonneg_of_nonpos` in a more generalized form.
created_at: 2025-04-06T22:31:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x < 0) (hy' : 0 < y) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_pos_of_neg (x y : Int) (hx' : 0 < x) (hy' : y < 0) :
+    - x ≤ x / y := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: In fact, you can make this `0 <= x`, too, AFAIU.
created_at: 2025-04-06T22:39:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: There are other ediv theorems higher up in the file. I feel these theorems may belong there.
created_at: 2025-04-06T22:40:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-07T05:59:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: removed `nonneg_ediv_of_neg_of_neg` 
created_at: 2025-04-07T06:00:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x < 0) (hy' : 0 < y) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done, all hypotheses are `\le` now
created_at: 2025-04-07T06:00:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x < 0) (hy' : 0 < y) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_pos_of_neg (x y : Int) (hx' : 0 < x) (hy' : y < 0) :
+    - x ≤ x / y := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done for both hypotheses
created_at: 2025-04-07T06:00:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-!
+  needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem nonneg_ediv_of_neg_of_neg (x y : Int) (hx' : x < 0) (hy' : y < 0) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, ofNat_eq_coe, Int.natCast_add, cast_ofNat_Int]
+  norm_cast
+  simp
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x < 0) (hy' : 0 < y) :
+    x ≤ x / y := by
+  simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+    show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+  apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_pos_of_neg (x y : Int) (hx' : 0 < x) (hy' : y < 0) :
+    - x ≤ x / y := by
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  rw [Int.div_def]
+  unfold Int.ediv
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
+  apply Nat.le_trans (m := xn) (by exact Nat.div_le_self xn (yn + 1)) (by omega)
+
+theorem nonpos_ediv_of_pos_of_neg (x y : Int) (hx' : 0 < x) (hy' : y < 0) :
+    x / y ≤ 0  := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: removed `nonpos_ediv_of_pos_of_neg`
created_at: 2025-04-07T06:00:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: I tried to do this, but it would require a major restructuring of the file, as some theorems that are below that section are needed to prove the ones in this PR
created_at: 2025-04-07T06:01:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: so I'd rather upstream this PR first and then consider moving the theorems, in a subsequent PR, if that can be useful
created_at: 2025-04-07T06:02:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2354,6 +2354,76 @@ theorem bmod_neg_bmod : bmod (-(bmod x n)) n = bmod (-x) n := by
   apply (bmod_add_cancel_right x).mp
   rw [Int.add_left_neg, ← add_bmod_bmod, Int.add_left_neg]
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_lt (x y : Int) (hx' : 0 < x) (hy' : 1 < y) :
+    x / y < x := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  apply Nat.div_lt_self (by omega) (by omega)
+
+-- note that x < y → x / y = 0
+theorem nonneg_ediv_of_pos_of_nonneg (x y : Int) (hx' : 0 < x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: updated the name
created_at: 2025-04-07T06:03:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5005,6 +5094,23 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdivOverflow_eq_negOverflow_of_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
+    sdivOverflow x y = negOverflow x := by
+  simp only [sdivOverflow, hy, toInt_allOnes, Int.reduceNeg, ge_iff_le, negOverflow]
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp only [Nat.add_one_sub_one, Nat.zero_lt_succ, ↓reduceIte, Int.reduceNeg, Int.ediv_neg,
+      Int.ediv_one, Int.neg_lt_neg_iff]
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp only [bool_to_prop]
+    by_cases hx : x.toInt = - 2 ^ w
+    · simp [hx]
+    · simp [show ¬x.toInt == -2 ^ w by simp only [beq_iff_eq, hx, not_false_eq_true]]; omega
+
+theorem not_sdivOverflow_eq_sdiv_lt_two_pow_neg_two_pow_le_sdiv {w : Nat} {x y : BitVec w} :
+    ¬ sdivOverflow x y = (- 2 ^ (w - 1) ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1)) := by
+  simp [sdivOverflow]; omega
+
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: ```suggestion


```
created_at: 2025-04-07T06:47:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: I am not the biggest fan of including the lower bounds in these conditions. I feel they lead to very specialized theorems. I proved the following for you:

```lean
theorem le_toInt_ediv_toInt {x y : BitVec w} :
    -(2^(w-1): Nat) ≤  x.toInt / y.toInt := by
  have : 0 ≤ (2 ^ (w - 1)) := by simp
  have x_lt := @toInt_lt w x; norm_cast at x_lt
  have le_x := @le_toInt w x; norm_cast at le_x

  by_cases xnonneg : 0 ≤ x.toInt
  · by_cases ynonneg : 0 ≤ y.toInt
    · have := @Int.ediv_nonneg_of_pos_of_nonneg x.toInt y.toInt xnonneg ynonneg
      omega
    · have := Int.neg_self_le_ediv_of_pos_of_neg x.toInt y.toInt xnonneg (by omega)
      omega
  · by_cases ynonneg : 0 ≤ y.toInt
    · have := @Int.self_le_ediv_of_neg_of_pos x.toInt y.toInt (by omega) ynonneg
      omega
    · have := @Int.ediv_nonneg_of_nonpos_of_nonpos x.toInt y.toInt (by omega) (by omega)
      omega
```

Do you think this would allow for further cleanups?
created_at: 2025-04-07T07:06:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: thank you, I've used it. I'm trying to prove (based on this) something like "when signs are discordant, the signed div is negative"
created_at: 2025-04-07T20:15:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: Not sure what this means. I would just include this at the top of sdivOverflow_eq and drop all lower-bound constraints that are now unnecessary from `zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos`, `neg_two_pow_le_sdiv_and_sdiv_lt_zero_of_neg_of_pos_of_zero_lt`, `neg_two_pow_le_sdiv_and_sdiv_le_zero_of_pos_of_neg_of_zero_lt`, and `zero_le_sdiv_and_sdiv_lt_two_pow_of_neg_of_lt_neg_one`. This would allow for simpler names for these theorems and maybe lead to follow-up simplifications.
created_at: 2025-04-07T20:23:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: yes that I've done - but I have not pushed yet because I would like to also have 
```lean4
theorem sdiv_le_zero_of_sign_ne {w : Nat} {x y : BitVec w} (hw : 0 < w):
    (x.toInt / y.toInt ≤ 0) ↔ (x.toInt = 0 ∨ y.toInt = 0 ∨ (x.toInt.sign ≠ y.toInt.sign)) := by sorry
```
created_at: 2025-04-07T20:24:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: Maybe push and clean the intermediate state and then let's see where things are? The other one would obviously be cute. But its likely a bit harder to prove.
created_at: 2025-04-07T20:28:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: Also, why do you want to prove the above. AFAIU you just need to prove that `x.toInt / y.toInt ≤ 2^(w-1)` (with a couple of exceptions).
created_at: 2025-04-07T20:29:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-07T20:30:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: The latest changes do not yet compile for me. :-)
created_at: 2025-04-07T20:36:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: me neither sadly :( fixing it now
created_at: 2025-04-07T20:37:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I thought they would when I committed
created_at: 2025-04-07T20:37:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_le_zero_of_neg_of_pos_of_zero_lt {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) (hw : 0 < w) :
+    x.toInt / y.toInt ≤ 0 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: You can name this as `sdiv_nonpos_of_nonpos_of_nonneg`
created_at: 2025-04-07T20:37:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_le_zero_of_neg_of_pos_of_zero_lt {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) (hw : 0 < w) :
+    x.toInt / y.toInt ≤ 0 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: You can also drop the `0 < w`
created_at: 2025-04-07T20:38:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: This name requires updating.
created_at: 2025-04-07T20:40:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: should be fixed now
created_at: 2025-04-07T20:41:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_le_zero_of_neg_of_pos_of_zero_lt {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) (hw : 0 < w) :
+    x.toInt / y.toInt ≤ 0 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-07T20:45:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) (hw : 0 < w) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · omega
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_two_pow_of_neg_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: I feel you should be able to prove:

```lean
theorem sdiv_lt_of_ne_allOnes {w : Nat} {x y : BitVec w} (h : y ≠ allOnes w) :
    x.toInt / y.toInt < 2 ^ (w - 1) := sorry
```
created_at: 2025-04-07T20:45:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) (hw : 0 < w) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · omega
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_two_pow_of_neg_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-07T20:46:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
    x.toInt / y.toInt < 2 ^ (w - 1) := by
```
created_at: 2025-04-07T20:46:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-07T20:47:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
   x.toInt / y.toInt ≤ 0 := by
```
created_at: 2025-04-07T20:48:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-07T20:49:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) (hw : 0 < w) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · omega
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_two_pow_of_neg_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: The definition is still different. :-) I am not sure this 100% works, but it might be useful.
created_at: 2025-04-07T20:50:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) (hw : 0 < w) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · omega
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_two_pow_of_neg_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: However, you would still need to prove it.
created_at: 2025-04-07T20:50:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) (hw : 0 < w) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · omega
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_two_pow_of_neg_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: oh no sorry I misread the comment and thought you were proposing a new name - will fix that (and prove the theorem) soon
created_at: 2025-04-08T04:43:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_pos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) (hw : 0 < w) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · omega
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_two_pow_of_neg_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: however, there is one cases in which the theorem does not hold: `#eval (1#1).toInt/(1#1).toInt < 2 ^ 0`. I would personally rather leave the `lt`, instead of adding another hypotheses on `w` (and have changed the name back to what it was)
created_at: 2025-04-08T05:02:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4116,6 +4116,103 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+#eval (1#1).toInt/(1#1).toInt < 2 ^ 0
+
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: ```suggestion


```
created_at: 2025-04-08T20:57:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4026,6 +4026,95 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem zero_le_sdiv_and_sdiv_lt_two_pow_of_pos_of_pos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    0 ≤ x.toInt / y.toInt ∧ x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: Spent some more time thinking about `sdiv_le_zero_of_sign_ne`: since it seems to be quite a long proof, I would like to push this PR forward and then potentially write the theorem in a subsequenty pr.
created_at: 2025-04-13T15:31:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,103 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: ```suggestion
```
created_at: 2025-04-13T15:41:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: ```suggestion
/-- Unsigned division never overflows. -/
```
created_at: 2025-04-13T16:24:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5137,6 +5232,19 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdivOverflow_eq_negOverflow_of_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
+    sdivOverflow x y = negOverflow x := by
+  simp only [sdivOverflow, hy, toInt_allOnes, Int.reduceNeg, ge_iff_le, negOverflow]
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp only [Nat.add_one_sub_one, Nat.zero_lt_succ, ↓reduceIte, Int.reduceNeg, Int.ediv_neg,
+      Int.ediv_one, Int.neg_lt_neg_iff]
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp only [bool_to_prop]
+    by_cases hx : x.toInt = - 2 ^ w
+    · simp [hx]
+    · simp [show ¬x.toInt == -2 ^ w by simp only [beq_iff_eq, hx, not_false_eq_true]]; omega
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: I'm a bit surprised that this proof is so long! In my naive imagination, we should that `x / allOnes w = -x`, and the result immediately follows that sdiv overflowing is equivalent to negation overflowing in this case. 

If this proof strategy does not work, a comment clarifying why this proof strategy does not work would be appreiated!
created_at: 2025-04-13T16:29:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.toInt_allOnes_sdiv_toInt_of_ne_zero (y := y) (by omega)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+-- signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt
+theorem neg_two_pow_le_sdiv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: 
```suggestion
/-- For bitvectors `x, y` of width `w`, `-2 ^ w` is a lower bound of `x.toInt / y.toInt`.
theorem neg_two_pow_le_toInt_div_toInt {x y : BitVec w} :
    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
```

I suggest a new theorem name, since the theorem, as far as I can tell, is not about `sdiv` at all, but rather a bound about `x.toInt / y.toInt`. 


created_at: 2025-04-13T16:32:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: ```suggestion
/-- Signed division is nonpositive when numerator and denominator are nonpositive. -/
theorem toInt_sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
   (x / y).toInt ≤ 0 := by
```


It is not clear to me that the theorem should say `sdiv...`. I feel it should either say `toInt_sdiv` and the theorem statement should be changed to talk about `(x / y).toInt`. 
created_at: 2025-04-13T16:35:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem toInt_allOnes_div_toInt_of_lt_one {w : Nat} {y : BitVec w} (hw : 1 < w) :
    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
```

IIUC, the integer operation is called `div`, so we should reflect that in the theorem name. Also, our hypothesis is that `1 < w`. Also, I find this theorem counterintuitive, so an explanation would help 😅 

created_at: 2025-04-13T16:37:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-13T16:43:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5137,6 +5232,19 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdivOverflow_eq_negOverflow_of_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
+    sdivOverflow x y = negOverflow x := by
+  simp only [sdivOverflow, hy, toInt_allOnes, Int.reduceNeg, ge_iff_le, negOverflow]
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp only [Nat.add_one_sub_one, Nat.zero_lt_succ, ↓reduceIte, Int.reduceNeg, Int.ediv_neg,
+      Int.ediv_one, Int.neg_lt_neg_iff]
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp only [bool_to_prop]
+    by_cases hx : x.toInt = - 2 ^ w
+    · simp [hx]
+    · simp [show ¬x.toInt == -2 ^ w by simp only [beq_iff_eq, hx, not_false_eq_true]]; omega
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I cleaned the proof to be slightly shorter, however, I don't think it can be any better. 
with commit d81efdf66d, right before `by_cases`, the proof state is:
`decide (2 ^ w ≤ -x.toInt) = (x.toInt == -2 ^ w)`
where the def of overflow for `sdiv` (based on the interval) clashes with the def of overflow for `neg` (based on an equality). AFAICT, changing the strategy to decouple the lt/eq case on the lhs would make the proof more complex than it already is. However, I might be missing some pieces - please let me know if this is the case!
created_at: 2025-04-13T16:52:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.toInt_allOnes_sdiv_toInt_of_ne_zero (y := y) (by omega)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+-- signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt
+theorem neg_two_pow_le_sdiv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I see. In this case, I would expect to unfold the `sdiv` operation (`BitVec.sdiv_eq`) and match based on the `msb` (instead of the signs of `toInt`) and _then_ refer to the corresponding `Int.*` theorems. I am not sure which of these strategies is better, suggestions are welcome.
created_at: 2025-04-13T18:45:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: same as prev. comment
created_at: 2025-04-13T18:45:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: Correct, I think the correct name according to `Int` nomenclature is actually `ediv` and will update it. 
I added this theorem after observing the following
```lean
#eval (-1) / 5 = -1
#eval (-1) / (-5) = 1
```
as opposed to 
```lean
#eval 1 / 5 = 0
#eval 1 / (-5) = 0
```
I personally found this observation very important to understand and correctly use signed division (and `emod` and `ediv` definitions), and therefore wanted to point it out with a theorem. 
I'm happy to add the following comment: 
`Given any integer y : Int different than 0, the signed division -1/y will always be -1 (if y is positive) or 1 (if y is negative). This is due to the definition of ediv for signed integer division, which these theorems reference.`
created_at: 2025-04-13T18:56:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.toInt_allOnes_sdiv_toInt_of_ne_zero (y := y) (by omega)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+-- signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt
+theorem neg_two_pow_le_sdiv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I fundamentally see two ways in which we can prove this set of `sdivOverflow`-related theorems: 
1. base these theorems on `sdiv` (e.g. `x.sdiv y`) and based on the `msb` of `x` and `y` reference different `ediv` theorems 
2. use `toInt` and directly refer `Int.ediv` operation reasoning about the signs of `toInt` (current strategy)
I'm also happy to switch to (1) and open a new PR to anyways upstream the theorems I wrote using `toInt` (I believe they are anyways useful). @tobiasgrosser, I'd be interested to know what you think of this!
created_at: 2025-04-13T19:02:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: It might make sense to quote from:

> The Euclidean Definition of the Functions div and mod (https://dl.acm.org/doi/pdf/10.1145/128861.128862)

which analyzes `ediv/emod`, `tdiv/tmod` , and `fdiv/fmod` in great detail.

--- 


As I recall, the explanation is as follows. Given `n, d`, we want to find numbers `q, r` (for `ediv/emod`) such that `q = n.ediv d` and `r = n.emod d` such that  `0 <= r < d`, and `n = q * d + r`. This is saying that `r` is the smallest non-negative integer that is equivalent modulo `d` to `n`. 

- Now, consider the case where `d` is non-negative (e.g. `d = 5`). If we now have `n = -1`, we get `r = 5 - 1 = 4` as the smallest non-negative number which is equivalent to `-1` modulo `5`. Furthermore, since `n = q * d + r`, we know that `q = (n - r)/d`, which in this case becomes `q = (-1 - (d - 1))/d` = (-1 - d + 1)/d = -d/d = -1`. So, the result of the division, the quotient, is `-1`.

- By a symmetric argument, we can argue that `q = 1` hen `d` is non-positive. 


--- 

I'm not sure how best to condense the above into a good explanation for the person reading the file. Happy to bounce on this a couple times :)  
created_at: 2025-04-13T23:07:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I've updated the docstring to be more informative. However, I don't think we should explain `emod` and `ediv` here entirely (they are explained already in `Int/DivMod/Basic`), so I'd rather keep the explanation succint. 
created_at: 2025-04-14T07:06:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,101 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+-- unsigned division never overflows
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+-- non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg
+theorem sdiv_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is negative, denumerator is positive
+theorem sdiv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+-- non-overflowing signed division bounds when numerator is positive, denumerator is negative
+theorem sdiv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+theorem toInt_allOnes_sdiv_toInt_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+-- non-overflowing signed division bounds when numerator is non positive, denumerator is less than one
+theorem sdiv_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.toInt_allOnes_sdiv_toInt_of_ne_zero (y := y) (by omega)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+-- signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt
+theorem neg_two_pow_le_sdiv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I have now updated the names of the theorems using `toInt`, but will soon open a new PR with the corresponding `sdiv` statements.
created_at: 2025-04-15T07:59:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
    x.toNat / y.toNat < 2 ^ w := by
```

- AFAIU `/` on type Nat is just named `div`.
- There are two toNat on the LHS. AFAIU they should both be used in the name.
created_at: 2025-04-18T07:03:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: okay, so should I also rename all the other ones to `toInt_ediv_toInt_*`?
created_at: 2025-04-18T07:07:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: Yes, I just am heading for breakfast but was interrupted in my review. Can you carefully look over the names. I will make a pass later today.
created_at: 2025-04-18T07:13:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
```
created_at: 2025-04-18T07:18:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
```
created_at: 2025-04-18T07:18:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_of_allOnes_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: `of_ne_zero`, either drop the of (as this is just about w) or rename it to `of_one_lt`.
created_at: 2025-04-18T07:20:53Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: doen
created_at: 2025-04-18T07:21:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-18T07:21:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_of_allOnes_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
```
created_at: 2025-04-18T07:21:45Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done for all `BitVec.toInt_ediv_*` theorems
created_at: 2025-04-18T07:21:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_of_allOnes_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-18T07:22:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_of_allOnes_of_ne_zero {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: dropped `of_ne_zero`
created_at: 2025-04-18T07:24:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_of_allOnes {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.toInt_ediv_toInt_of_allOnes (y := y) (by omega)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+/-- Signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt. -/
+theorem neg_two_pow_le_toInt_ediv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem le_toInt_ediv_toInt {x y : BitVec w} :
    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
```
created_at: 2025-04-18T09:46:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
    x.toNat / y.toNat < 2 ^ w := by
```


created_at: 2025-04-18T09:46:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
```
created_at: 2025-04-18T09:47:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I'm not sure about this, it seems like `udiv` is used: 
- https://leanprover-community.github.io/mathlib4_docs/Init/Data/BitVec/Lemmas.html#BitVec.toNat_udiv
- https://leanprover-community.github.io/mathlib4_docs/Init/Data/BitVec/Bitblast.html#BitVec.udiv_eq_of_mul_add_toNat

whenever `toNat` is applied to a bitvector (and `ediv` when `toInt` is applied, afaict)
created_at: 2025-04-18T12:00:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-18T12:04:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_of_allOnes {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.toInt_ediv_toInt_of_allOnes (y := y) (by omega)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+/-- Signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt. -/
+theorem neg_two_pow_le_toInt_ediv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: for consistency with the other overflow-related theorems naming, I'd rather maintain the `neg_two` in the name.
created_at: 2025-04-18T12:59:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: These two uses of `udiv` refer to `BitVec.udiv`, not `Nat.div`:

```lean
@[simp, bitvec_to_nat]
theorem toNat_udiv {x y : BitVec n} : (x / y).toNat = x.toNat / y.toNat := by
  rfl
```

the above is equivalent to:

```lean
@[simp, bitvec_to_nat]
theorem toNat_udiv {x y : BitVec n} : BitVec.toNat (x / y) = x.toNat / y.toNat := by
  rfl
```

So the `toNat_udiv` refers to the functions `BitVec.toNat` and `/` which in this case is `BitVec.udiv`.

In the second example we have:

```lean
theorem udiv_eq_of_mul_add_toNat {d n q r : BitVec w} (hd : 0 < d)
    (hrd : r < d)
    (hdqnr : d.toNat * q.toNat + r.toNat = n.toNat) :
    n / d = q 
```

Here `n` and `d` are both of type `BitVec`, which means the `/` is `BitVec.udiv`, not `Nat.div`.

All uses of `/` on the type `Nat` use the name `div`, e.g., https://leanprover-community.github.io/mathlib4_docs/Init/Data/Nat/Div/Basic.html#Nat.div_eq_of_lt. Hence, I would suggest to stay with `div`. Does this seem consistent to you?
created_at: 2025-04-20T18:05:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
```

Sorry, I may have asked for sth different, but if we say `nonpos` we do not need the `le_`, no?
created_at: 2025-04-20T18:06:27Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
```
created_at: 2025-04-20T18:06:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
```

I may have made the same mistake as above, but `_le` is not needed if we say `_nonpos`.
created_at: 2025-04-20T18:07:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_eq_of_allOnes {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < -1)  :
```

created_at: 2025-04-20T18:08:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_of_allOnes {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have hy := eq_zero_or_eq_one (a := y)
+    simp [← toInt_inj, toInt_zero, toInt_one] at hy
+    omega
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    have hx' : x.toInt = 0 ∨ x.toInt = - 1 ∨ x.toInt < - 1 := by omega
+    rcases hx' with hx'|hx'|hx'
+    · simp [hx']; omega
+    · have := BitVec.toInt_ediv_toInt_of_allOnes (y := y) (by omega)
+      simp only [toInt_allOnes, Nat.lt_add_left_iff_pos, Nat.zero_lt_succ, ↓reduceIte,
+        Int.reduceNeg] at this
+      simp [hx', this]
+      omega
+    · have := Int.ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x := x.toInt) (y := y.toInt) (by omega) hy
+      simp; omega
+
+/-- Signed division of (x y : BitVec w) is always -2 ^ w ≤ x.toInt / y.toInt. -/
+theorem neg_two_pow_le_toInt_ediv {x y : BitVec w} :
+    - 2 ^ (w - 1) ≤ x.toInt / y.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: Thank you for looking into this carefully. I guess you are referring to:

```lean
theorem two_pow_le_toInt_mul_toInt_iff {x y : BitVec w} :
    2 ^ (w - 1) ≤ x.toInt * y.toInt ...
```

You also seem to add:
```lean
theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
    x.toInt / y.toInt < 2 ^ (w - 1) := by
```

and we already have:

```lean
theorem toNat_mul_toNat_lt {x y : BitVec w} : x.toNat * y.toNat < 2 ^ (w * 2) := by
  have := BitVec.isLt x; have := BitVec.isLt y
  simp only [Nat.mul_two, Nat.pow_add]
  exact Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
```

As well as many `toNat_lt`, `le_toNat` variants, all without `two_pow`. 

This is already inconsistent in the existing codebase. Statistically, it seems that cases without `two_pow` are more common.


created_at: 2025-04-20T18:16:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: sure it does, I've updated it
created_at: 2025-04-20T21:35:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-20T21:40:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_eq_of_allOnes {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [hw]; omega
+  · simp [hw]; omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_lt_allOnes {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-20T21:40:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-20T21:40:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_udiv_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Nnon-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_le_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-20T21:40:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with width `0 < w`, this happens iff `x = intMin` and `y = allOnes w`.
path: src/Init/Data/BitVec/Basic.lean
user: login: bollu
body: ```suggestion
For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
```

Following the comment style for `negOverflow`. 
created_at: 2025-04-21T17:09:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  set the bounds of signed division for integers.
path: src/Init/Data/BitVec/Bitblast.lean
user: login: bollu
body: ```suggestion
  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
  propagate bounds for signed division for integers.
```

I would not use the word 'set', since that has an imperative flavour. I would say "propagate bounds", ala [bounds propagation](https://en.wikipedia.org/wiki/Propagation_of_uncertainty).
created_at: 2025-04-21T17:12:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_eq_of_allOnes {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: Is `(allOnes w).toInt` in simp-normal-form?
created_at: 2025-04-21T17:15:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5137,6 +5240,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_allOnes {w : Nat} {x : BitVec w} :
+    x.toInt / (allOnes w).toInt = - x.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: is `(allOnes w).toInt` in simp NF?
created_at: 2025-04-21T17:18:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2415,6 +2415,65 @@ theorem dvd_iff_bmod_eq_zero {a : Nat} {b : Int} : (a : Int) ∣ b ↔ b.bmod a
       simp_all
       omega
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one (x y : Int) (hx' : 0 < x) (hy' : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_pos_of_nonneg (x y : Int) (hx' : 0 ≤ x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-- Needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true. -/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x ≤ 0) (hy' : 0 ≤ y) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem self_le_ediv_of_nonpos_of_nonneg (x y : Int) (hx' : x ≤ 0) (hy' : 0 ≤ y) :
```
created_at: 2025-04-21T17:20:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2415,6 +2415,65 @@ theorem dvd_iff_bmod_eq_zero {a : Nat} {b : Int} : (a : Int) ∣ b ↔ b.bmod a
       simp_all
       omega
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one (x y : Int) (hx' : 0 < x) (hy' : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_pos_of_nonneg (x y : Int) (hx' : 0 ≤ x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-- Needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true. -/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x ≤ 0) (hy' : 0 ≤ y) :
+    x ≤ x / y := by
+  by_cases hx : x = 0
+  · simp [hx, zero_ediv]
+  · by_cases hy : y = 0
+    · simp [hy]; omega
+    · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+        show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+      apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_pos_of_neg (x y : Int) (hx' : 0 ≤ x) (hy' : y ≤ 0) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx' : 0 ≤ x) (hy' : y ≤ 0) :
```
created_at: 2025-04-21T17:20:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2415,6 +2415,65 @@ theorem dvd_iff_bmod_eq_zero {a : Nat} {b : Int} : (a : Int) ∣ b ↔ b.bmod a
       simp_all
       omega
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one (x y : Int) (hx' : 0 < x) (hy' : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_pos_of_nonneg (x y : Int) (hx' : 0 ≤ x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-- Needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true. -/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: bollu
body: I think this needs a more descriptive comment, and the `{x y : Int}` should be implicit, and also, I'd imagine that the hypotheses ought to be named `hx, hy`.

Finally, it's not totally clear to me why we prove the theorem only in the case where `x, y` are negative: What about the other three cases of `x positive, y negative`, `x positive, y positive`, and `x negative, y positive`? 

It is out of scope for this PR. A subsequent PR filling in the API to `Int.ediv` to bound the division by the numerator in the other three cases would be useful. 
created_at: 2025-04-21T17:24:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with width `0 < w`, this happens iff `x = intMin` and `y = allOnes w`.
path: src/Init/Data/BitVec/Basic.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-21T17:34:37Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  set the bounds of signed division for integers.
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: accepted
created_at: 2025-04-21T17:35:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4139,6 +4139,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_eq_of_allOnes {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    (allOnes w).toInt / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: It is not. However, the NF is `if 0 < w then -1 else 0`, which I personally don't particularly like (also bc given the `if` I can not use `hw` to get rid of it within `simp`). I thus went for `-1` directly and changed the name accordingly.
created_at: 2025-04-21T17:39:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5137,6 +5240,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_allOnes {w : Nat} {x : BitVec w} :
+    x.toInt / (allOnes w).toInt = - x.toInt := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: same as before, it is not so I changed to `-1` and updated the name
created_at: 2025-04-21T17:41:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2415,6 +2415,65 @@ theorem dvd_iff_bmod_eq_zero {a : Nat} {b : Int} : (a : Int) ∣ b ↔ b.bmod a
       simp_all
       omega
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one (x y : Int) (hx' : 0 < x) (hy' : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_pos_of_nonneg (x y : Int) (hx' : 0 ≤ x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-- Needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true. -/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x ≤ 0) (hy' : 0 ≤ y) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: updated
created_at: 2025-04-21T17:42:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2415,6 +2415,65 @@ theorem dvd_iff_bmod_eq_zero {a : Nat} {b : Int} : (a : Int) ∣ b ↔ b.bmod a
       simp_all
       omega
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one (x y : Int) (hx' : 0 < x) (hy' : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_pos_of_nonneg (x y : Int) (hx' : 0 ≤ x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-- Needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true. -/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx, hy, Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_neg_of_pos (x y : Int) (hx' : x ≤ 0) (hy' : 0 ≤ y) :
+    x ≤ x / y := by
+  by_cases hx : x = 0
+  · simp [hx, zero_ediv]
+  · by_cases hy : y = 0
+    · simp [hy]; omega
+    · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+        show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+      apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_pos_of_neg (x y : Int) (hx' : 0 ≤ x) (hy' : y ≤ 0) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-21T17:42:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2415,6 +2415,65 @@ theorem dvd_iff_bmod_eq_zero {a : Nat} {b : Int} : (a : Int) ∣ b ↔ b.bmod a
       simp_all
       omega
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one (x y : Int) (hx' : 0 < x) (hy' : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_pos_of_nonneg (x y : Int) (hx' : 0 ≤ x) (hy' : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx, hy, Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/-- Needs a stricter bound on x, in fact (-1)/(-2) = 1 and 1 < (-1).natAbs is not true. -/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one (x y : Int) (hx' : x < -1) (hy' : y < -1) :
+    x / y < x.natAbs := by
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: fixed implicit argoments and hypotheses names in this and all the nearby theorems.

All the other cases are covered already in this PR. This theorem is spiritually the `x nonpos y nonpos` one, however, it is only true that  `x / y < x.natAbs` with the stricter condition of `y < -1` and `x < -1` and not simply nonpos. I made the comment (hopefully?) clearer.

Moreover, this theorem is used in the proof of `BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one`. 
created_at: 2025-04-21T17:51:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp [toInt_allOnes]
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: I wonder if this should be an `Int` theorem of the form `forall (x : Int), x / -1 = -x`. Let's do this in a subsequent PR even if we want to :) 
created_at: 2025-04-21T21:26:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp [toInt_allOnes]
+
+theorem sdivOverflow_eq_negOverflow_of_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem sdivOverflow_eq_negOverflow_of_eq_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
```
created_at: 2025-04-21T21:27:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_eq_of_neg_one {w : Nat} {y : BitVec w} (hw : 1 < w) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem neg_one_toInt_ediv_toInt_eq_of_lt_one {w : Nat} {y : BitVec w} (hw : 1 < w) :
```

I believe the suggestion should be the theorem name, to say that we have `-1 / y`, and that the hypothesis is `(1 < w)`.
created_at: 2025-04-21T21:28:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,73 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: bollu
body: ```suggestion
theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
```

I think it should be `of_ne_one` since we are saying that `(hy : y ≠ 1)`, not `1 ≠ 1`.
created_at: 2025-04-21T21:29:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp [toInt_allOnes]
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: sure, happy to do that in a subsequent PR.
created_at: 2025-04-21T21:37:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp [toInt_allOnes]
+
+theorem sdivOverflow_eq_negOverflow_of_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-21T21:38:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_one_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem toInt_ediv_toInt_eq_of_neg_one {w : Nat} {y : BitVec w} (hw : 1 < w) :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-21T21:39:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,73 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_one_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: thanks for the catch!! it is indeed, fixed now.
created_at: 2025-04-21T21:48:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    -1 / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · omega
+  · omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < - 1)  :
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < -1)  :
```
created_at: 2025-04-22T05:50:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,73 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+
+/--  When both x and y are negative we need stricter bounds on x and y
+  to establish the upper bound of x/y, i.e., x / y < x.natAbs.
+  In particular, consider the following counter examples:
+  · (-1) / (-2) = 1 and ¬ 1 < (-1).natAbs
+    (note that Int.neg_one_ediv already handles `ediv` where the numerator is -1)
+  · (-2) / (-1) = 2 and ¬ 1 < (-2).natAbs
+  To exclude these cases, we enforce stricter bounds on the values of x and y.
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one {x y : Int} (hx : x < -1) (hy : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx', hy', Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_nonpos_of_nonneg {x y : Int} (hx : x ≤ 0) (hy : 0 ≤ y) :
+    x ≤ x / y := by
+  by_cases hx' : x = 0
+  · simp [hx', zero_ediv]
+  · by_cases hy : y = 0
+    · simp [hy]; omega
+    · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+        show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+      apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx : 0 ≤ x) (hy : y ≤ 0) :
+    - x ≤ x / y := by
+  by_cases hy' : y = 0
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
    -x ≤ x / y := by
  by_cases hy' : y = 0
```
created_at: 2025-04-22T05:51:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: The part of the comment after the `when` lines is outdated. Do we really need to repeat the information that is already encoded in the theorem name? Also, the code meanwhile seems relatively self-documenting. I wonder if we want to have this comment at all?
created_at: 2025-04-22T07:30:08Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: Not sure this is relevant. If that is of interest, people can look it up, no?
created_at: 2025-04-22T07:30:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: If we want to clean this up further we can likely flip the `x` and `y` cases. There seems no reason to treat them in opposite order, no?
created_at: 2025-04-22T07:33:16Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+      · by_cases hx : 0 < x.toInt
+        · -- numerator is positive, denumerator is negative
+          have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator and denumerator are negative
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
          simp; omega
        · -- numerator and denumerator are negative
```
created_at: 2025-04-22T07:35:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+      · by_cases hx : 0 < x.toInt
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
          simp; omega
      · by_cases hx : 0 < x.toInt
```
created_at: 2025-04-22T07:35:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
      simp only [sdivOverflow, hy]
```
created_at: 2025-04-22T07:36:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+      · by_cases hx : 0 < x.toInt
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
      · by_cases hx : 0 ≤ x.toInt
```

For symmetry, this can be changed to `≤`.
created_at: 2025-04-22T07:37:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    -1 / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · omega
+  · omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: Do we need this comment? It seems just to paraphrase the theorem statement.
created_at: 2025-04-22T07:38:49Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    -1 / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: This is not cleaned up, but the proof does not require `hw`:

```lean
theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} :
    -1 / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
  rcases w with _|_|w
  · simp [BitVec.eq_nil y]
  · dsimp at y
    have := eq_zero_or_eq_one y
    cases this
    case succ.zero.inl h =>
      simp [h]
    case succ.zero.inr h =>
      simp [h]
  · by_cases 0 < y.toInt
    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
      omega
    · by_cases hy : y.toInt = 0
      · simp [hy]
      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
        omega
```
created_at: 2025-04-22T07:43:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,73 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion

```
created_at: 2025-04-22T07:44:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,73 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: When I read this comment and try to make the connection with the proof, I fail to make this connection.

How is this comment related? Is it needed? 
created_at: 2025-04-22T07:46:04Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp [toInt_allOnes]
+
+theorem sdivOverflow_eq_negOverflow_of_eq_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
+    sdivOverflow x y = negOverflow x := by
+  rcases w with _|w
+  · simp [sdivOverflow, negOverflow, of_length_zero]
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp only [sdivOverflow, hy, toInt_allOnes, Nat.zero_lt_succ, ↓reduceIte, Int.reduceNeg,
+      Int.ediv_neg, Int.ediv_one, Nat.add_one_sub_one, ge_iff_le, Int.neg_lt_neg_iff,
+      show ¬2 ^ w < x.toInt by omega, decide_false, Bool.or_false, negOverflow]
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
    simp only [sdivOverflow, hy, show ¬2 ^ w < x.toInt by omega, negOverflow]
```
created_at: 2025-04-22T07:48:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: This comment is out-of-date. Do we really need these comments? They seem to just paraphrase the theorem statement. 
created_at: 2025-04-22T07:50:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: shortened
created_at: 2025-04-22T08:01:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: removed
created_at: 2025-04-22T08:02:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
    x.toInt / -1 = -x.toInt := by
  rcases w with _|w
```
created_at: 2025-04-22T08:08:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: flipped
created_at: 2025-04-22T08:38:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+      · by_cases hx : 0 < x.toInt
+        · -- numerator is positive, denumerator is negative
+          have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator and denumerator are negative
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: this does not work (`omega` cant solve it because of a `+ 1 - 1` in the hypothesis introduced) 
created_at: 2025-04-22T08:38:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+      · by_cases hx : 0 < x.toInt
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: same, does not work
created_at: 2025-04-22T08:39:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: accepted
created_at: 2025-04-22T08:40:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+      · by_cases hx : 0 < x.toInt
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: accepted
created_at: 2025-04-22T08:41:23Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    -1 / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: accepted (and golfed)
created_at: 2025-04-22T08:45:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,73 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: done
created_at: 2025-04-22T08:46:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,73 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+/-- Note that x < y → 0 ≤ x → 0 ≤ y → x / y = 0 -/
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: removed the comment - I think it belonged to a previous version of the theorem
created_at: 2025-04-22T08:46:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · simp [toInt_allOnes]
+
+theorem sdivOverflow_eq_negOverflow_of_eq_allOnes {w : Nat} {x y : BitVec w} (hy : y = allOnes w) :
+    sdivOverflow x y = negOverflow x := by
+  rcases w with _|w
+  · simp [sdivOverflow, negOverflow, of_length_zero]
+  · have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    simp only [sdivOverflow, hy, toInt_allOnes, Nat.zero_lt_succ, ↓reduceIte, Int.reduceNeg,
+      Int.ediv_neg, Int.ediv_one, Nat.add_one_sub_one, ge_iff_le, Int.neg_lt_neg_iff,
+      show ¬2 ^ w < x.toInt by omega, decide_false, Bool.or_false, negOverflow]
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-22T08:48:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -5140,6 +5243,24 @@ theorem sub_le_sub_iff_le {x y z : BitVec w} (hxz : z ≤ x) (hyz : z ≤ y) :
     BitVec.toNat_sub_of_le (by rw [BitVec.le_def]; omega)]
   omega
 
+theorem sdiv_neg_one {w : Nat} {x : BitVec w} :
+    x.toInt / -1 = - x.toInt := by
+  rcases w with _|w
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed

created_at: 2025-04-22T08:49:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} (hw : 1 < w) :
+    -1 / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · omega
+  · omega
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: I would prefer leaving the comments. I updated them to be correct and consistent with the theorem statement, but I think it does not hurt to have them (people can just ignore them if the meaning of the theorem is trivial).
created_at: 2025-04-22T08:51:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,109 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is positive, denumerator is negative. -/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: same as above
created_at: 2025-04-22T08:51:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,112 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denumerator is nonpos. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} :
+    (-1) / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have := eq_zero_or_eq_one y
+    cases this
+    · case _ h => simp [h]
+    · case _ h => simp [h]
+  · by_cases 0 < y.toInt
+    · simp [Int.sign_eq_one_of_pos (a := y.toInt) (by omega), Int.neg_one_ediv]
+      omega
+    · by_cases hy : y.toInt = 0
+      · simp [hy]
+      · simp [Int.sign_eq_neg_one_of_neg (a := y.toInt) (by omega), Int.neg_one_ediv]
+        omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denumerator is less than -1. -/
+theorem toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < -1)  :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
path: src/Init/Data/BitVec/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
theorem toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : y.toInt < -1) :
    x.toInt / y.toInt < 2 ^ (w - 1) := by
```
created_at: 2025-04-22T09:11:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
  · simp only [Int.div_def, Int.ediv]
```

?
created_at: 2025-04-22T09:13:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
  simp only [Int.div_def, Int.ediv]
```
?
created_at: 2025-04-22T09:14:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/--  When both x and y are negative we need stricter bounds on x and y
+  to establish the upper bound of x/y, i.e., x / y < x.natAbs.
+  In particular, consider the following counter examples:
+  · (-1) / (-2) = 1 and ¬ 1 < (-1).natAbs
+    (note that Int.neg_one_ediv already handles `ediv` where the numerator is -1)
+  · (-2) / (-1) = 2 and ¬ 1 < (-2).natAbs
+  To exclude these cases, we enforce stricter bounds on the values of x and y.
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one {x y : Int} (hx : x < -1) (hy : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
  simp only [Int.div_def, Int.ediv]
```
created_at: 2025-04-22T09:14:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/--  When both x and y are negative we need stricter bounds on x and y
+  to establish the upper bound of x/y, i.e., x / y < x.natAbs.
+  In particular, consider the following counter examples:
+  · (-1) / (-2) = 1 and ¬ 1 < (-1).natAbs
+    (note that Int.neg_one_ediv already handles `ediv` where the numerator is -1)
+  · (-2) / (-1) = 2 and ¬ 1 < (-2).natAbs
+  To exclude these cases, we enforce stricter bounds on the values of x and y.
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one {x y : Int} (hx : x < -1) (hy : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx', hy', Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_nonpos_of_nonneg {x y : Int} (hx : x ≤ 0) (hy : 0 ≤ y) :
+    x ≤ x / y := by
+  by_cases hx' : x = 0
+  · simp [hx', zero_ediv]
+  · by_cases hy : y = 0
+    · simp [hy]; omega
+    · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+        show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+      apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx : 0 ≤ x) (hy : y ≤ 0) :
+    -x ≤ x / y := by
+  by_cases hy' : y = 0
+  · simp [hy']; omega
+  · obtain ⟨xn, hx''⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy''⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+    rw [Int.div_def]
+    unfold Int.ediv
+    simp only [hx'', hy'', Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: ```suggestion
    simp only [Int.div_def, Int.ediv, hx'', hy'', Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
```
?
created_at: 2025-04-22T09:14:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: this does not work
created_at: 2025-04-22T09:15:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: same as above
created_at: 2025-04-22T09:15:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/--  When both x and y are negative we need stricter bounds on x and y
+  to establish the upper bound of x/y, i.e., x / y < x.natAbs.
+  In particular, consider the following counter examples:
+  · (-1) / (-2) = 1 and ¬ 1 < (-1).natAbs
+    (note that Int.neg_one_ediv already handles `ediv` where the numerator is -1)
+  · (-2) / (-1) = 2 and ¬ 1 < (-2).natAbs
+  To exclude these cases, we enforce stricter bounds on the values of x and y.
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one {x y : Int} (hx : x < -1) (hy : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: same

created_at: 2025-04-22T09:15:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/--  When both x and y are negative we need stricter bounds on x and y
+  to establish the upper bound of x/y, i.e., x / y < x.natAbs.
+  In particular, consider the following counter examples:
+  · (-1) / (-2) = 1 and ¬ 1 < (-1).natAbs
+    (note that Int.neg_one_ediv already handles `ediv` where the numerator is -1)
+  · (-2) / (-1) = 2 and ¬ 1 < (-2).natAbs
+  To exclude these cases, we enforce stricter bounds on the values of x and y.
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one {x y : Int} (hx : x < -1) (hy : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx', hy', Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_nonpos_of_nonneg {x y : Int} (hx : x ≤ 0) (hy : 0 ≤ y) :
+    x ≤ x / y := by
+  by_cases hx' : x = 0
+  · simp [hx', zero_ediv]
+  · by_cases hy : y = 0
+    · simp [hy]; omega
+    · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+        show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+      apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx : 0 ≤ x) (hy : y ≤ 0) :
+    -x ≤ x / y := by
+  by_cases hy' : y = 0
+  · simp [hy']; omega
+  · obtain ⟨xn, hx''⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy''⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+    rw [Int.div_def]
+    unfold Int.ediv
+    simp only [hx'', hy'', Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: luisacicolini
body: this breaks the proof. I can look into it and fix it if necessary, but the proof looked good already imho
created_at: 2025-04-22T09:18:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,60 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when
+  x = intMin w and y = allOnes w (for 0 < w).
+
+  To show that this is the *only* case in which overflow happens, we refer to
+  overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_eq_allOnes):
+  in fact, x.toInt/(allOnes w).toInt = - x.toInt, i.e.,
+  the overflow conditions are the same as negOverflow for x.
+
+  We can then reason about the signs of the operands. All these cases rely on respective
+  theorems specifying the bounds of signed division once the special cases are excluded:
+  · BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg when 0 < y.toInt and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg when 0 < y.toInt and x.toInt < 0
+  · BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos when y.toInt < 0 and 0 < x.toInt
+  · BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one when y.toInt < -1 and x.toInt < 0
+
+  These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully
+  propagate bounds for signed division for integers.
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, Nat.add_one_sub_one, ge_iff_le, hy, _root_.and_false,
+          decide_false, or_eq_false_iff, decide_eq_false_iff_not, Int.not_le, Int.not_lt]
+      simp only [bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hy' : 0 ≤ y.toInt
+      · by_cases hx : 0 ≤ x.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+      · by_cases hx : 0 < x.toInt
+        · -- numerator is positive, denumerator is negative
+          have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator and denumerator are negative
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: I pushed 0065b54160e49d19049c5766e1d7a22f813d4d29.
created_at: 2025-04-22T09:21:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
+
+/--  When both x and y are negative we need stricter bounds on x and y
+  to establish the upper bound of x/y, i.e., x / y < x.natAbs.
+  In particular, consider the following counter examples:
+  · (-1) / (-2) = 1 and ¬ 1 < (-1).natAbs
+    (note that Int.neg_one_ediv already handles `ediv` where the numerator is -1)
+  · (-2) / (-1) = 2 and ¬ 1 < (-2).natAbs
+  To exclude these cases, we enforce stricter bounds on the values of x and y.
+-/
+theorem ediv_lt_natAbs_self_of_lt_neg_one_of_lt_neg_one {x y : Int} (hx : x < -1) (hy : y < -1) :
+    x / y < x.natAbs := by
+  rw [Int.div_def]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_negSucc_of_lt_zero (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+  simp only [hx', hy', Nat.succ_eq_add_one, Int.ofNat_eq_coe, Int.natCast_add, Int.cast_ofNat_Int]
+  norm_cast
+  rw [natAbs_negSucc, Nat.succ_eq_add_one, Nat.add_lt_add_iff_right,
+    Nat.div_lt_iff_lt_mul (x := xn) (k := yn + 1) (y := xn) (by omega),
+    show (xn < xn * (yn + 1)) = (1 * xn < (yn + 1) * xn) by rw [Nat.one_mul, Nat.mul_comm]]
+  apply Nat.mul_lt_mul_of_lt_of_le (a := 1) (b := xn) (c := yn + 1) (d := xn) (by omega) (by omega) (by omega)
+
+theorem self_le_ediv_of_nonpos_of_nonneg {x y : Int} (hx : x ≤ 0) (hy : 0 ≤ y) :
+    x ≤ x / y := by
+  by_cases hx' : x = 0
+  · simp [hx', zero_ediv]
+  · by_cases hy : y = 0
+    · simp [hy]; omega
+    · simp only [ge_iff_le, Int.le_ediv_iff_mul_le (c := y) (a := x) (b := x) (by omega),
+        show (x * y ≤ x) = (x * y ≤ x * 1) by rw [Int.mul_one], Int.mul_one]
+      apply Int.mul_le_mul_of_nonpos_left (a := x) (b := y) (c  := (1 : Int)) (by omega) (by omega)
+
+theorem neg_self_le_ediv_of_nonneg_of_nonpos (x y : Int) (hx : 0 ≤ x) (hy : y ≤ 0) :
+    -x ≤ x / y := by
+  by_cases hy' : y = 0
+  · simp [hy']; omega
+  · obtain ⟨xn, hx''⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy''⟩ := Int.eq_negSucc_of_lt_zero (a := y) (by omega)
+    rw [Int.div_def]
+    unfold Int.ediv
+    simp only [hx'', hy'', Nat.succ_eq_add_one, Int.ofNat_eq_coe, ge_iff_le, Int.neg_le_neg_iff, Int.ofNat_le]
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: Let's leave it then. :+1: 
created_at: 2025-04-22T09:21:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: tobiasgrosser
body: OK, let's close this then.
created_at: 2025-04-22T09:22:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
        · -- numerator and denominator are nonnegative
          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
```
created_at: 2025-04-22T09:24:43Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is positive, denumerator is negative
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
        · -- numerator is nonnegative, denominator is negative
```
created_at: 2025-04-22T09:24:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is positive, denumerator is negative
+          have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
        · -- numerator is negative, denumerator is positive
          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
```
```suggestion
        · -- numerator is negative, denominator is nonnegative
          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
```
created_at: 2025-04-22T09:25:51Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is positive, denumerator is negative
+          have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+        · -- numerator and denumerator are negative
+          have := BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one
+                (x := x) (y := y) (by omega) (by rw [← toInt_inj, toInt_allOnes] at hy; omega)
path: src/Init/Data/BitVec/Bitblast.lean
user: login: tobiasgrosser
body: ```suggestion
        · -- numerator and denominator are negative
          have := BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one
                (x := x) (y := y) (by omega) (by rw [← toInt_inj, toInt_allOnes] at hy; omega)
```
created_at: 2025-04-22T09:26:00Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is positive, denumerator is negative
+          have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-22T09:29:40Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is positive, denumerator is negative
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-22T09:29:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-22T09:30:54Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denumerator are positive
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp only [Nat.add_one_sub_one] at this; simp; omega
+        · -- numerator is positive, denumerator is negative
+          have := BitVec.toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator is negative, denumerator is positive
+          have :=  BitVec.toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg
+                (x := x) (y := y) (by omega) (by omega)
+          simp; omega
+        · -- numerator and denumerator are negative
+          have := BitVec.toInt_ediv_toInt_lt_of_nonpos_of_lt_neg_one
+                (x := x) (y := y) (by omega) (by rw [← toInt_inj, toInt_allOnes] at hy; omega)
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-22T09:31:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
+
+SMT-LIB name: `bvsdivo`.
+-/
+def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
+  (x.toInt / y.toInt ≥ 2 ^ (w - 1)) || (x.toInt / y.toInt < - 2 ^ (w - 1))
path: src/Init/Data/BitVec/Basic.lean
user: login: hargoniX
body: Dont we usually use `≤`?
created_at: 2025-04-22T09:47:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
path: src/Init/Data/BitVec/Bitblast.lean
user: login: hargoniX
body: ```suggestion
      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y)
      simp only [Nat.add_one_sub_one] at this
```
created_at: 2025-04-22T09:49:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
path: src/Init/Data/BitVec/Bitblast.lean
user: login: hargoniX
body: ```suggestion
  · have yle := le_two_mul_toInt (x := y)
    have ylt := two_mul_toInt_lt (x := y)
```
created_at: 2025-04-22T09:49:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denominator are nonneg
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
path: src/Init/Data/BitVec/Bitblast.lean
user: login: hargoniX
body: Not quite sure about this indentation style, does it have any precedence case? It's also used inconsequentially, e.g. line 4153 in BitVec.Lemmas is long but not split over multiple lines in this fashion.
created_at: 2025-04-22T09:52:07Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,112 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
path: src/Init/Data/BitVec/Lemmas.lean
user: login: hargoniX
body: Non terminal simp
created_at: 2025-04-22T09:55:20Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,112 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denominator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonpos. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} :
+    (-1) / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have := eq_zero_or_eq_one y
+    cases this
path: src/Init/Data/BitVec/Lemmas.lean
user: login: hargoniX
body: ```suggestion
  · cases eq_zero_or_eq_one y
```
created_at: 2025-04-22T09:56:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
path: src/Init/Data/BitVec/Bitblast.lean
user: login: hargoniX
body: ```suggestion
  Prove that signed division `x.toInt / y.toInt` only overflows when `x = intMin w` and `y = allOnes w` (for 0 < w).
```
created_at: 2025-04-22T09:56:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,112 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denominator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonpos. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: hargoniX
body: ```suggestion
/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
  we have that for two integers `x` and `y`: `x/y = q ↔ x.ediv y = q ↔ r = x.emod y`
  and in particular: `-1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y`.
  from which it follows that:
  ```
  (-1)/0 = 0
  (-1)/y = -1 when 0 < y
  (-1)/(-5) = 1 when y < 0
  ```
-/
```
I guess?
created_at: 2025-04-22T09:57:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
+
+SMT-LIB name: `bvsdivo`.
+-/
+def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
+  (x.toInt / y.toInt ≥ 2 ^ (w - 1)) || (x.toInt / y.toInt < - 2 ^ (w - 1))
path: src/Init/Data/BitVec/Basic.lean
user: login: luisacicolini
body: changed def to 
```lean4
def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
  (x.toInt / y.toInt ≥ 2 ^ (w - 1)) || (x.toInt / y.toInt ≤  - 2 ^ (w - 1) - 1)
```
created_at: 2025-04-22T14:07:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: done
created_at: 2025-04-22T14:08:29Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: done
created_at: 2025-04-22T14:08:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denominator are nonneg
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: it does not - I removed the comments about signs, since the theorems' names and docstrings should be clear anyways
created_at: 2025-04-22T14:09:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
+
+SMT-LIB name: `bvsdivo`.
+-/
+def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
+  (x.toInt / y.toInt ≥ 2 ^ (w - 1)) || (x.toInt / y.toInt < - 2 ^ (w - 1))
path: src/Init/Data/BitVec/Basic.lean
user: login: tobiasgrosser
body: That does not look right. It still has >=.
created_at: 2025-04-22T14:09:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
+-/
+theorem sdivOverflow_eq {w : Nat} (x y : BitVec w) :
+    (sdivOverflow x y) = (decide (0 < w) && (x = intMin w) && (y = allOnes w)) := by
+  rcases w with _|w
+  · simp [sdivOverflow, of_length_zero]
+  · have yle := le_two_mul_toInt (x := y); have ylt := two_mul_toInt_lt (x := y)
+    -- treat case x.toInt / - 1
+    -- if y = allOnes (w + 1), thus y.toInt = -1
+    -- the division overflows iff x = intMin (w + 1), as for negation
+    by_cases hy : y = allOnes (w + 1)
+    · simp [sdivOverflow_eq_negOverflow_of_eq_allOnes, negOverflow_eq, ← hy, beq_eq_decide_eq]
+    · -- reason about signs
+      simp only [sdivOverflow, hy, bool_to_prop]
+      have := BitVec.neg_two_pow_le_toInt_ediv (x := x) (y := y); simp only [Nat.add_one_sub_one] at this
+      by_cases hx : 0 ≤ x.toInt
+      · by_cases hy' : 0 ≤ y.toInt
+        · -- numerator and denominator are nonneg
+          have := BitVec.toInt_ediv_toInt_lt_of_nonneg_of_nonneg
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: (same for `BitVec.Lemmas`)
created_at: 2025-04-22T14:09:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,112 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-22T14:10:19Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,112 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denominator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonpos. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
+theorem neg_one_ediv_toInt_eq {w : Nat} {y : BitVec w} :
+    (-1) / y.toInt = if y.toInt = 0 then 0 else if 0 < y.toInt then -1 else 1 := by
+  rcases w with _|_|w
+  · simp [of_length_zero]
+  · have := eq_zero_or_eq_one y
+    cases this
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed 
created_at: 2025-04-22T14:10:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1359,6 +1359,42 @@ theorem negOverflow_eq {w : Nat} (x : BitVec w) :
     simp only [toInt_intMin, Nat.add_one_sub_one, Int.ofNat_emod, Int.neg_inj]
     rw_mod_cast [Nat.mod_eq_of_lt (by simp [Nat.pow_lt_pow_succ])]
 
+/--
+  Prove that signed division x.toInt / y.toInt only overflows when x = intMin w and y = allOnes w (for 0 < w).
path: src/Init/Data/BitVec/Bitblast.lean
user: login: luisacicolini
body: done
created_at: 2025-04-22T14:11:26Z
author_association: CONTRIBUTOR
diff_hunk: @@ -4143,6 +4143,112 @@ theorem sdiv_self {x : BitVec w} :
       rcases x.msb with msb | msb <;> simp
     · rcases x.msb with msb | msb <;> simp [h]
 
+/-- Unsigned division never overflows. -/
+theorem toNat_div_toNat_lt {w : Nat} {x y : BitVec w} :
+    x.toNat / y.toNat < 2 ^ w := by
+  have hy : y.toNat = 0 ∨ y.toNat = 1 ∨ 1 < y.toNat := by omega
+  rcases hy with hy|hy|hy
+  · simp [hy]; omega
+  · simp [hy]; omega
+  · rw [Nat.div_lt_iff_lt_mul (k := y.toNat) (x := x.toNat) (y := 2 ^ w) (by omega), show x.toNat = x.toNat * 1 by omega]
+    apply Nat.mul_lt_mul_of_le_of_lt (by omega) (by omega) (by omega)
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonneg. -/
+theorem toInt_ediv_toInt_lt_of_nonneg_of_nonneg {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt < 2 ^ (w - 1) := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · -- if y.toInt = 1 and 0 < x.toInt, then x.toInt / 1 = x.toInt < 2 ^ w
+    have xle := le_two_mul_toInt (x := x); have xlt := two_mul_toInt_lt (x := x)
+    by_cases hy' : y.toInt = 1
+    · simp [hy', Int.ediv_one]; omega
+    · by_cases hx' : x.toInt = 0
+      · simp [hx']
+        norm_cast
+        exact Nat.two_pow_pos (w := w)
+      · have := Int.ediv_lt_self_of_pos_of_ne_one (x := x.toInt) (y := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonpos, denominator is nonneg. -/
+theorem toInt_ediv_toInt_nonpos_of_nonpos_of_nonneg {w : Nat} {x y : BitVec w} (hx : x.toInt ≤ 0) (hy : 0 ≤ y.toInt) :
+    x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hx' : x.toInt = 0
+    · simp [hx']
+    · by_cases hy' : y.toInt = 0
+      · simp [hy']
+      · have := Int.ediv_neg_of_neg_of_pos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+        simp; omega
+
+/-- Non-overflowing signed division bounds when numerator is nonneg, denominator is nonpos. -/
+theorem toInt_ediv_toInt_nonpos_of_nonneg_of_nonpos {w : Nat} {x y : BitVec w} (hx : 0 ≤ x.toInt) (hy : y.toInt ≤ 0) :
+   x.toInt / y.toInt ≤ 0 := by
+  rcases w with _|w
+  · simp [of_length_zero]
+  · by_cases hy' : y.toInt = -1
+    · simp [hy']; omega
+    · have := Int.ediv_nonpos_of_nonneg_of_nonpos (a := x.toInt) (b := y.toInt) (by omega) (by omega)
+      simp; omega
+
+/-- Given the definition of ediv/emod for signed integer division (https://dl.acm.org/doi/pdf/10.1145/128861.128862)
+  we have that for two integers x and y: x/y = q ↔ x.ediv y = q ↔ r = x.emod y
+  and in particular: -1/y = q ↔ -1.ediv y = q ↔ r = -1.emod y.
+  from which it follows that:
+  (-1)/0 = 0
+  (-1)/y = -1 when 0 < y
+  (-1)/(-5) = 1 when y < 0
+-/
path: src/Init/Data/BitVec/Lemmas.lean
user: login: luisacicolini
body: fixed
created_at: 2025-04-22T14:13:24Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
+
+SMT-LIB name: `bvsdivo`.
+-/
+def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
+  (x.toInt / y.toInt ≥ 2 ^ (w - 1)) || (x.toInt / y.toInt < - 2 ^ (w - 1))
path: src/Init/Data/BitVec/Basic.lean
user: login: luisacicolini
body: my bad, I thought the problem was changing `<` to `\le`. now changed to 
```lean4
def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
  (2 ^ (w - 1) ≤ x.toInt / y.toInt) || (x.toInt / y.toInt ≤  - 2 ^ (w - 1) - 1)
```
created_at: 2025-04-22T14:16:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
+
+SMT-LIB name: `bvsdivo`.
+-/
+def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
+  (x.toInt / y.toInt ≥ 2 ^ (w - 1)) || (x.toInt / y.toInt < - 2 ^ (w - 1))
path: src/Init/Data/BitVec/Basic.lean
user: login: tobiasgrosser
body: The right part sould remain `<`. No need to turn it into `<=` and then add a `- 1`.
created_at: 2025-04-22T14:55:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -767,6 +767,15 @@ SMT-Lib name: `bvnego`.
 def negOverflow {w : Nat} (x : BitVec w) : Bool :=
   x.toInt == - 2 ^ (w - 1)
 
+/--
+Checks whether the signed division of `x` by `y` results in overflow.
+For BitVecs `x` and `y` with nonzero width, this only happens if `x = intMin` and `y = allOnes w`.
+
+SMT-LIB name: `bvsdivo`.
+-/
+def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
+  (x.toInt / y.toInt ≥ 2 ^ (w - 1)) || (x.toInt / y.toInt < - 2 ^ (w - 1))
path: src/Init/Data/BitVec/Basic.lean
user: login: luisacicolini
body: updated to 
```
def sdivOverflow {w : Nat} (x y : BitVec w) : Bool :=
  (2 ^ (w - 1) ≤ x.toInt / y.toInt) || (x.toInt / y.toInt <  - 2 ^ (w - 1))
  ```
created_at: 2025-04-22T15:26:52Z
author_association: CONTRIBUTOR
diff_hunk: @@ -2894,6 +2894,71 @@ theorem bmod_eq_self_of_le_mul_two {x : Int} {y : Nat} (hle : -y ≤ x * 2) (hlt
     x.bmod y = x :=
   bmod_eq_of_le_mul_two hle hlt
 
+/- ### ediv -/
+
+theorem ediv_lt_self_of_pos_of_ne_one {x y : Int} (hx : 0 < x) (hy : y ≠ 1) :
+    x / y < x := by
+  by_cases hy' : 1 < y
+  · rw [Int.div_def]
+    unfold Int.ediv
+    obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+    obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+    simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+    apply Nat.div_lt_self (by omega) (by omega)
+  · have := @Int.ediv_nonpos_of_nonneg_of_nonpos x y (by omega) (by omega)
+    omega
+
+theorem ediv_nonneg_of_nonneg_of_nonneg {x y : Int} (hx : 0 ≤ x) (hy : 0 ≤ y) :
+    0 ≤ x / y := by
+  rw [Int.div_def, ]
+  unfold Int.ediv
+  obtain ⟨xn, hx'⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
+  obtain ⟨yn, hy'⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
+  simp only [hx', hy', Int.ofNat_eq_coe, Int.ofNat_lt]
+  exact Int.ofNat_zero_le (xn / yn)
path: src/Init/Data/Int/DivMod/Lemmas.lean
user: login: TwoFX
body: Please try to avoid `Int.div_dev` and unfolding `Int.ediv`. This should never be necessary. For example, this proof can just be
```suggestion
  obtain ⟨xn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := x) (by omega)
  obtain ⟨yn, rfl⟩ := Int.eq_ofNat_of_zero_le (a := y) (by omega)
  rw [← Int.ofNat_ediv]
  exact Int.ofNat_zero_le (xn / yn)
```
Similar changes are possible in the lemmas above and below.
created_at: 2025-04-23T15:07:08Z
author_association: MEMBER

PR comments:
user: login: ghost
created_at: 2025-03-24T23:38:59Z
body: Mathlib CI status ([docs](https://leanprover-community.github.io/contribute/tags_and_branches.html)):
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase b0e58d3387ec103287ac56aea95e4cecd9968982 --onto 635af865bf52013210057ebfb99bec4c04f40cab`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-03-24 23:38:59)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase b0e58d3387ec103287ac56aea95e4cecd9968982 --onto 2edfe2e9cffd55e3c79291628ae091b942291ec9`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-01 15:46:30)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 33e456dd3cde9b8413c78e1b7ecc87b5cce42f46 --onto 911ea07a73733650eefa5240652404856bdcceb7`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-02 16:03:37)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 33e456dd3cde9b8413c78e1b7ecc87b5cce42f46 --onto 1ee7e1a9d8a67d1d8dcf6a17ac5c92bc2c7e0fac`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-03 09:15:51)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 83067d67d65efe4818205ddb3f9b2ab824735b10 --onto 1ee7e1a9d8a67d1d8dcf6a17ac5c92bc2c7e0fac`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-03 15:50:08)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 83067d67d65efe4818205ddb3f9b2ab824735b10 --onto da55b2e19b6af219f43f3599f1a72151799eb524`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-06 06:56:13)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase ab4febd1df0382982335ef9b0161043d6b996ba8 --onto 0f2ede45d50d8fc8cc542517867a9d6a29f805a3`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-08 08:31:44)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase ab4febd1df0382982335ef9b0161043d6b996ba8 --onto bfed22330660045ea0641543a969ce79d1ef65b0`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-08 21:19:38)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 973f521c469da9268921672c36a8007d5c09fc2c --onto deef1c2739a331899b0e536312e65e9815059014`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-13 16:04:35)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase c3996aadb8d70e9d2d99bd054dcb305ff03ccfd2 --onto deef1c2739a331899b0e536312e65e9815059014`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-15 08:29:04)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase c3996aadb8d70e9d2d99bd054dcb305ff03ccfd2 --onto 689acab1d3490913f353c32fdffc05e9d7a26fdf`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-15 14:52:40)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase c3996aadb8d70e9d2d99bd054dcb305ff03ccfd2 --onto 020b8834c3e06da1cd1682431b6fa8d52206c8ec`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-18 07:48:51)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase c3996aadb8d70e9d2d99bd054dcb305ff03ccfd2 --onto de27872f3ffee8f2eb13f36fbb8fec9bcdfe3b8c`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-20 22:08:15)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 791bba0091134bfc0bc3c94fb688c84fc59c90b7 --onto de27872f3ffee8f2eb13f36fbb8fec9bcdfe3b8c`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-21 19:00:14)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 791bba0091134bfc0bc3c94fb688c84fc59c90b7 --onto 02f7a1dd41f034939acf49a5c2c590076cb26d8e`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-22 07:13:58)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase 8e1b9abb7a707ac6080af2f29581dd7bcfd2fcc5 --onto 02f7a1dd41f034939acf49a5c2c590076cb26d8e`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-22 15:24:56)
- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the `nightly-with-mathlib` branch. Try `git rebase ad3ac150bcc357d13d868b97c0df6282c911da40 --onto 02f7a1dd41f034939acf49a5c2c590076cb26d8e`. You can force Mathlib CI using the `force-mathlib-ci` label. (2025-04-22 21:26:54)
author_association: NONE
user: login: luisacicolini
created_at: 2025-04-01T15:16:27Z
body: changelog-library
author_association: CONTRIBUTOR
user: login: bollu
created_at: 2025-04-15T14:09:42Z
body: > I fundamentally see two ways in which we can prove this set of `sdivOverflow`-related theorems:
> 
> 1. base these theorems on `sdiv` (e.g. `x.sdiv y`) and based on the `msb` of `x` and `y` reference different `ediv` theorems
> 2. use `toInt` and directly refer `Int.ediv` operation reasoning about the signs of `toInt` (current strategy)
>    I'm also happy to switch to (1) and open a new PR to anyways upstream the theorems I wrote using `toInt` (I believe they are anyways useful). @tobiasgrosser, I'd be interested to know what you think of this!


@luisacicolini I don't see why we need a new PR. I feel the theorems, as they currently exist (e.g. `neg_two_pow_le_toInt_div_toInt`) are properly named, and have the correct theorem statement. Let's get this PR to be merged first, and add more lemmas in a subsequent PR!
author_association: CONTRIBUTOR
user: login: bollu
created_at: 2025-04-15T14:11:45Z
body: BTW, I made an oopsie in suggesting names: It should be `Int.ediv_...` for theorems that mention `a / b` for `a, b : Int`. So we should name `neg_two_pow_le_toInt_div_toInt` as `neg_two_pow_le_toInt_ediv_toInt`, but that's the only change we should make! 
author_association: CONTRIBUTOR
user: login: tobiasgrosser
created_at: 2025-04-15T14:18:31Z
body: @luisacicolini, I think we just need to do a final pass on the theorem names as @bollu suggested. Otherwise, this seems to be ready to ship. 
author_association: CONTRIBUTOR
user: login: luisacicolini
created_at: 2025-04-15T14:26:43Z
body: thank you @tobiasgrosser @bollu. The names should be correct already, if the PR looks good for you I'm happy to open it.
author_association: CONTRIBUTOR
user: login: tobiasgrosser
created_at: 2025-04-15T14:29:45Z
body: Let me do a pass tonight. 
author_association: CONTRIBUTOR
user: login: luisacicolini
created_at: 2025-04-15T14:31:02Z
body: > Let me do a pass tonight.

sure - no hurry!
author_association: CONTRIBUTOR
user: login: tobiasgrosser
created_at: 2025-04-22T05:53:29Z
body: The commit message also requires an update.
author_association: CONTRIBUTOR
user: login: tobiasgrosser
created_at: 2025-04-22T09:23:17Z
body: > These BitVec theorems themselves rely on numerous Int.udiv_* theorems, that carefully set the bounds of signed division for integers.

Should these be `Int.ediv`?
author_association: CONTRIBUTOR
user: login: luisacicolini
created_at: 2025-04-22T14:20:18Z
body: thank you @hargoniX, I've addressed the comments
author_association: CONTRIBUTOR
user: login: luisacicolini
created_at: 2025-04-24T06:22:41Z
body: thanks @TwoFX, I avoided unfolding and updated the proofs :)
author_association: CONTRIBUTOR