l3lab/ntp-mathlib huggingface dataset:
@[simp]
theorem testBit_bitwise (f : Bool → Bool → Bool) (m n k) :
    testBit (bitwise f m n) k = f (testBit m k) (testBit n k) := by
  cases m <;> cases n <;> simp only [testBit, bitwise, natBitwise]
  · by_cases h : f false false <;> simp [h]
  · by_cases h : f false true <;> simp [h]
  · by_cases h : f true false <;> 

Proof state:
case neg
f : Bool → Bool → Bool
k a✝¹ a✝ : ℕ
h : ¬f true false = true
⊢ (match
      bif f (!false) false then -[Nat.bitwise (fun x y => !f (!x) y) a✝¹ a✝+1]
      else ↑(Nat.bitwise (fun x y => f (!x) y) a✝¹ a✝),
      k with
    | ofNat m, n => Nat.testBit m n
    | -[m+1], n => !Nat.testBit m n) =
    f (!Nat.testBit a✝¹ k) (Nat.testBit a✝ k)

Next tactic:
simp [h]
@[simp]
theorem testBit_bitwise (f : Bool → Bool → Bool) (m n k) :
    testBit (bitwise f m n) k = f (testBit m k) (testBit n k) := by
  cases m <;> cases n <;> simp only [testBit, bitwise, natBitwise]
  · by_cases h : f false false <;> simp [h]
  · by_cases h : f false true <;> simp [h]
  · by_cases h : f true false <;> simp [h]
  · 

Proof state:
case negSucc.negSucc
f : Bool → Bool → Bool
k a✝¹ a✝ : ℕ
⊢ (match
      bif f (!false) !false then -[Nat.bitwise (fun x y => !f (!x) !y) a✝¹ a✝+1]
      else ↑(Nat.bitwise (fun x y => f (!x) !y) a✝¹ a✝),
      k with
    | ofNat m, n => Nat.testBit m n
    | -[m+1], n => !Nat.testBit m n) =
    f (!Nat.testBit a✝¹ k) !Nat.testBit a✝ k

Next tactic:
by_cases h : f true true
@[simp]
theorem testBit_bitwise (f : Bool → Bool → Bool) (m n k) :
    testBit (bitwise f m n) k = f (testBit m k) (testBit n k) := by
  cases m <;> cases n <;> simp only [testBit, bitwise, natBitwise]
  · by_cases h : f false false <;> simp [h]
  · by_cases h : f false true <;> simp [h]
  · by_cases h : f true false <;> simp [h]
  · by_cases h : f true true <;> 

Proof state:
case pos
f : Bool → Bool → Bool
k a✝¹ a✝ : ℕ
h : f true true = true
⊢ (match
      bif f (!false) !false then -[Nat.bitwise (fun x y => !f (!x) !y) a✝¹ a✝+1]
      else ↑(Nat.bitwise (fun x y => f (!x) !y) a✝¹ a✝),
      k with
    | ofNat m, n => Nat.testBit m n
    | -[m+1], n => !Nat.testBit m n) =
    f (!Nat.testBit a✝¹ k) !Nat.testBit a✝ k

Next tactic:
simp [h]
@[simp]
theorem testBit_bitwise (f : Bool → Bool → Bool) (m n k) :
    testBit (bitwise f m n) k = f (testBit m k) (testBit n k) := by
  cases m <;> cases n <;> simp only [testBit, bitwise, natBitwise]
  · by_cases h : f false false <;> simp [h]
  · by_cases h : f false true <;> simp [h]
  · by_cases h : f true false <;> simp [h]
  · by_cases h : f true true <;> 

Proof state:
case neg
f : Bool → Bool → Bool
k a✝¹ a✝ : ℕ
h : ¬f true true = true
⊢ (match
      bif f (!false) !false then -[Nat.bitwise (fun x y => !f (!x) !y) a✝¹ a✝+1]
      else ↑(Nat.bitwise (fun x y => f (!x) !y) a✝¹ a✝),
      k with
    | ofNat m, n => Nat.testBit m n
    | -[m+1], n => !Nat.testBit m n) =
    f (!Nat.testBit a✝¹ k) !Nat.testBit a✝ k

Next tactic:
simp [h]
@[simp]
theorem testBit_lor (m n k) : testBit (lor m n) k = (testBit m k || testBit n k) := by
  

Proof state:
m n : ℤ
k : ℕ
⊢ testBit (lor m n) k = (testBit m k || testBit n k)

Next tactic:
rw [← bitwise_or, testBit_bitwise]
@[simp]
theorem testBit_land (m n k) : testBit (land m n) k = (testBit m k && testBit n k) := by
  

Proof state:
m n : ℤ
k : ℕ
⊢ testBit (land m n) k = (testBit m k && testBit n k)

Next tactic:
rw [← bitwise_and, testBit_bitwise]
@[simp]
theorem testBit_ldiff (m n k) : testBit (ldiff m n) k = (testBit m k && not (testBit n k)) := by
  

Proof state:
m n : ℤ
k : ℕ
⊢ testBit (ldiff m n) k = (testBit m k && !testBit n k)

Next tactic:
rw [← bitwise_diff, testBit_bitwise]
@[simp]
theorem testBit_lxor (m n k) : testBit (Int.xor m n) k = xor (testBit m k) (testBit n k) := by
  

Proof state:
m n : ℤ
k : ℕ
⊢ testBit (Int.xor m n) k = xor (testBit m k) (testBit n k)

Next tactic:
rw [← bitwise_xor, testBit_bitwise]
@[simp]
theorem testBit_lnot : ∀ n k, testBit (lnot n) k = not (testBit n k)
  | (n : ℕ), k => by 

Proof state:
n k : ℕ
⊢ testBit (lnot ↑n) k = !testBit (↑n) k

Next tactic:
simp [lnot, testBit]
@[simp]
theorem testBit_lnot : ∀ n k, testBit (lnot n) k = not (testBit n k)
  | (n : ℕ), k => by simp [lnot, testBit]
  | -[n+1], k => by 

Proof state:
n k : ℕ
⊢ testBit (lnot -[n+1]) k = !testBit -[n+1] k

Next tactic:
simp [lnot, testBit]
@[simp]
theorem shiftRight_neg (m n : ℤ) : m >>> (-n) = m <<< n := by 

Proof state:
m n : ℤ
⊢ m >>> (-n) = m <<< n

Next tactic:
rw [← shiftLeft_neg, neg_neg]
@[simp]
theorem shiftLeft_coe_nat (m n : ℕ) : (m : ℤ) <<< (n : ℤ) = ↑(m <<< n) :=
  by 

Proof state:
m n : ℕ
⊢ ↑m <<< ↑n = ↑(m <<< n)

Next tactic:
simp [instShiftLeftInt, HShiftLeft.hShiftLeft]
@[simp]
theorem shiftRight_coe_nat (m n : ℕ) : (m : ℤ) >>> (n : ℤ) = m >>> n := by 

Proof state:
m n : ℕ
⊢ ↑m >>> ↑n = ↑(m >>> n)

Next tactic:
cases n
@[simp]
theorem shiftRight_coe_nat (m n : ℕ) : (m : ℤ) >>> (n : ℤ) = m >>> n := by cases n <;> 

Proof state:
case zero
m : ℕ
⊢ ↑m >>> ↑Nat.zero = ↑(m >>> Nat.zero)

Next tactic:
rfl
@[simp]
theorem shiftRight_coe_nat (m n : ℕ) : (m : ℤ) >>> (n : ℤ) = m >>> n := by cases n <;> 

Proof state:
case succ
m n✝ : ℕ
⊢ ↑m >>> ↑(Nat.succ n✝) = ↑(m >>> Nat.succ n✝)

Next tactic:
rfl
@[simp]
theorem shiftRight_negSucc (m n : ℕ) : -[m+1] >>> (n : ℤ) = -[m >>> n+1] := by 

Proof state:
m n : ℕ
⊢ -[m+1] >>> ↑n = -[m >>> n+1]

Next tactic:
cases n
@[simp]
theorem shiftRight_negSucc (m n : ℕ) : -[m+1] >>> (n : ℤ) = -[m >>> n+1] := by cases n <;> 

Proof state:
case zero
m : ℕ
⊢ -[m+1] >>> ↑Nat.zero = -[m >>> Nat.zero+1]

Next tactic:
rfl
@[simp]
theorem shiftRight_negSucc (m n : ℕ) : -[m+1] >>> (n : ℤ) = -[m >>> n+1] := by cases n <;> 

Proof state:
case succ
m n✝ : ℕ
⊢ -[m+1] >>> ↑(Nat.succ n✝) = -[m >>> Nat.succ n✝+1]

Next tactic:
rfl
theorem shiftRight_add : ∀ (m : ℤ) (n k : ℕ), m >>> (n + k : ℤ) = (m >>> (n : ℤ)) >>> (k : ℤ)
  | (m : ℕ), n, k => by
    

Proof state:
m n k : ℕ
⊢ ↑m >>> (↑n + ↑k) = ↑m >>> ↑n >>> ↑k

Next tactic:
rw [shiftRight_coe_nat, shiftRight_coe_nat, ← Int.ofNat_add, shiftRight_coe_nat,
      Nat.shiftRight_add]
theorem shiftRight_add : ∀ (m : ℤ) (n k : ℕ), m >>> (n + k : ℤ) = (m >>> (n : ℤ)) >>> (k : ℤ)
  | (m : ℕ), n, k => by
    rw [shiftRight_coe_nat, shiftRight_coe_nat, ← Int.ofNat_add, shiftRight_coe_nat,
      Nat.shiftRight_add]
  | -[m+1], n, k => by
    

Proof state:
m n k : ℕ
⊢ -[m+1] >>> (↑n + ↑k) = -[m+1] >>> ↑n >>> ↑k

Next tactic:
rw [shiftRight_negSucc, shiftRight_negSucc, ← Int.ofNat_add, shiftRight_negSucc,
      Nat.shiftRight_add]
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by 

Proof state:
m n k : ℕ
⊢ Nat.shiftLeft' false m (n + k) = Nat.shiftLeft' false (Nat.shiftLeft' false m n) k

Next tactic:
simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc]
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by 

Proof state:
m n✝ k i n : ℕ
⊢ (fun n k i => ↑m <<< i = ↑(Nat.shiftLeft' false m n >>> k)) (n + i) n ↑i

Next tactic:
dsimp
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; 

Proof state:
m n✝ k i n : ℕ
⊢ ↑m <<< ↑i = ↑(Nat.shiftLeft' false m (n + i) >>> n)

Next tactic:
simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left]
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        

Proof state:
m n✝ k i n : ℕ
⊢ (fun n k i => ↑m <<< i = ↑(Nat.shiftLeft' false m n >>> k)) n (n + i + 1) -[i+1]

Next tactic:
dsimp
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        dsimp
        

Proof state:
m n✝ k i n : ℕ
⊢ ↑m <<< -[i+1] = ↑(Nat.shiftLeft' false m n >>> (n + i + 1))

Next tactic:
simp [Nat.shiftLeft_zero, Nat.shiftRight_add, ← Nat.shiftLeft_sub]
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        dsimp
        simp [Nat.shiftLeft_zero, Nat.shiftRight_add, ← Nat.shiftLeft_sub]
        

Proof state:
m n✝ k i n : ℕ
⊢ ↑m <<< -[i+1] = ↑(m >>> i >>> 1)

Next tactic:
rfl
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        dsimp
        simp [Nat.shiftLeft_zero, Nat.shiftRight_add, ← Nat.shiftLeft_sub]
        rfl
  | -[m+1], n, -[k+1] =>
    subNatNat_elim n k.succ
      (fun n k i => -[m+1] <<< i = -[(Nat.shiftLeft' true m n) >>> k+1])
      (fun i n =>
        congr_arg negSucc <| by
          

Proof state:
m n✝ k i n : ℕ
⊢ Nat.shiftLeft' true m i = Nat.shiftLeft' true m (n + i) >>> n

Next tactic:
rw [← Nat.shiftLeft'_sub, add_tsub_cancel_left]
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        dsimp
        simp [Nat.shiftLeft_zero, Nat.shiftRight_add, ← Nat.shiftLeft_sub]
        rfl
  | -[m+1], n, -[k+1] =>
    subNatNat_elim n k.succ
      (fun n k i => -[m+1] <<< i = -[(Nat.shiftLeft' true m n) >>> k+1])
      (fun i n =>
        congr_arg negSucc <| by
          rw [← Nat.shiftLeft'_sub, add_tsub_cancel_left]; 

Proof state:
case a
m n✝ k i n : ℕ
⊢ n ≤ n + i

Next tactic:
apply Nat.le_add_right
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        dsimp
        simp [Nat.shiftLeft_zero, Nat.shiftRight_add, ← Nat.shiftLeft_sub]
        rfl
  | -[m+1], n, -[k+1] =>
    subNatNat_elim n k.succ
      (fun n k i => -[m+1] <<< i = -[(Nat.shiftLeft' true m n) >>> k+1])
      (fun i n =>
        congr_arg negSucc <| by
          rw [← Nat.shiftLeft'_sub, add_tsub_cancel_left]; apply Nat.le_add_right)
      fun i n =>
      congr_arg negSucc <| by 

Proof state:
m n✝ k i n : ℕ
⊢ m >>> Nat.succ i = Nat.shiftLeft' true m n >>> (n + i + 1)

Next tactic:
rw [add_assoc, Nat.shiftRight_add, ← Nat.shiftLeft'_sub, tsub_self]
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        dsimp
        simp [Nat.shiftLeft_zero, Nat.shiftRight_add, ← Nat.shiftLeft_sub]
        rfl
  | -[m+1], n, -[k+1] =>
    subNatNat_elim n k.succ
      (fun n k i => -[m+1] <<< i = -[(Nat.shiftLeft' true m n) >>> k+1])
      (fun i n =>
        congr_arg negSucc <| by
          rw [← Nat.shiftLeft'_sub, add_tsub_cancel_left]; apply Nat.le_add_right)
      fun i n =>
      congr_arg negSucc <| by rw [add_assoc, Nat.shiftRight_add, ← Nat.shiftLeft'_sub, tsub_self]
      <;> 

Proof state:
m n✝ k i n : ℕ
⊢ m >>> Nat.succ i = Nat.shiftLeft' true m 0 >>> (i + 1)

Next tactic:
rfl
theorem shiftLeft_add : ∀ (m : ℤ) (n : ℕ) (k : ℤ), m <<< (n + k) = (m <<< (n : ℤ)) <<< k
  | (m : ℕ), n, (k : ℕ) =>
    congr_arg ofNat (by simp [Nat.shiftLeft_eq, Nat.pow_add, mul_assoc])
  | -[m+1], n, (k : ℕ) => congr_arg negSucc (Nat.shiftLeft'_add _ _ _ _)
  | (m : ℕ), n, -[k+1] =>
    subNatNat_elim n k.succ (fun n k i => (↑m) <<< i = (Nat.shiftLeft' false m n) >>> k)
      (fun (i n : ℕ) =>
        by dsimp; simp [← Nat.shiftLeft_sub _ , add_tsub_cancel_left])
      fun i n => by
        dsimp
        simp [Nat.shiftLeft_zero, Nat.shiftRight_add, ← Nat.shiftLeft_sub]
        rfl
  | -[m+1], n, -[k+1] =>
    subNatNat_elim n k.succ
      (fun n k i => -[m+1] <<< i = -[(Nat.shiftLeft' true m n) >>> k+1])
      (fun i n =>
        congr_arg negSucc <| by
          rw [← Nat.shiftLeft'_sub, add_tsub_cancel_left]; apply Nat.le_add_right)
      fun i n =>
      congr_arg negSucc <| by rw [add_assoc, Nat.shiftRight_add, ← Nat.shiftLeft'_sub, tsub_self]
      <;> 

Proof state:
case a
m n✝ k i n : ℕ
⊢ n ≤ n

Next tactic:
rfl
theorem shiftLeft_eq_mul_pow : ∀ (m : ℤ) (n : ℕ), m <<< (n : ℤ) = m * (2 ^ n : ℕ)
  | (m : ℕ), _ => congr_arg ((↑) : ℕ → ℤ) (by 

Proof state:
m x✝ : ℕ
⊢ Nat.shiftLeft' false m x✝ = m * 2 ^ x✝

Next tactic:
simp [Nat.shiftLeft_eq]
theorem shiftRight_eq_div_pow : ∀ (m : ℤ) (n : ℕ), m >>> (n : ℤ) = m / (2 ^ n : ℕ)
  | (m : ℕ), n => by 

Proof state:
m n : ℕ
⊢ ↑m >>> ↑n = ↑m / ↑(2 ^ n)

Next tactic:
rw [shiftRight_coe_nat, Nat.shiftRight_eq_div_pow _ _]
theorem shiftRight_eq_div_pow : ∀ (m : ℤ) (n : ℕ), m >>> (n : ℤ) = m / (2 ^ n : ℕ)
  | (m : ℕ), n => by rw [shiftRight_coe_nat, Nat.shiftRight_eq_div_pow _ _]; 

Proof state:
m n : ℕ
⊢ ↑(m / 2 ^ n) = ↑m / ↑(2 ^ n)

Next tactic:
simp
theorem shiftRight_eq_div_pow : ∀ (m : ℤ) (n : ℕ), m >>> (n : ℤ) = m / (2 ^ n : ℕ)
  | (m : ℕ), n => by rw [shiftRight_coe_nat, Nat.shiftRight_eq_div_pow _ _]; simp
  | -[m+1], n => by
    

Proof state:
m n : ℕ
⊢ -[m+1] >>> ↑n = -[m+1] / ↑(2 ^ n)

Next tactic:
rw [shiftRight_negSucc, negSucc_ediv, Nat.shiftRight_eq_div_pow]
theorem shiftRight_eq_div_pow : ∀ (m : ℤ) (n : ℕ), m >>> (n : ℤ) = m / (2 ^ n : ℕ)
  | (m : ℕ), n => by rw [shiftRight_coe_nat, Nat.shiftRight_eq_div_pow _ _]; simp
  | -[m+1], n => by
    rw [shiftRight_negSucc, negSucc_ediv, Nat.shiftRight_eq_div_pow]; 

Proof state:
m n : ℕ
⊢ -[m / 2 ^ n+1] = -(div ↑m ↑(2 ^ n) + 1)
case H m n : ℕ ⊢ 0 < ↑(2 ^ n)

Next tactic:
rfl
theorem shiftRight_eq_div_pow : ∀ (m : ℤ) (n : ℕ), m >>> (n : ℤ) = m / (2 ^ n : ℕ)
  | (m : ℕ), n => by rw [shiftRight_coe_nat, Nat.shiftRight_eq_div_pow _ _]; simp
  | -[m+1], n => by
    rw [shiftRight_negSucc, negSucc_ediv, Nat.shiftRight_eq_div_pow]; rfl
    

Proof state:
case H
m n : ℕ
⊢ 0 < ↑(2 ^ n)

Next tactic:
exact ofNat_lt_ofNat_of_lt (pow_pos (by decide) _)
theorem shiftRight_eq_div_pow : ∀ (m : ℤ) (n : ℕ), m >>> (n : ℤ) = m / (2 ^ n : ℕ)
  | (m : ℕ), n => by rw [shiftRight_coe_nat, Nat.shiftRight_eq_div_pow _ _]; simp
  | -[m+1], n => by
    rw [shiftRight_negSucc, negSucc_ediv, Nat.shiftRight_eq_div_pow]; rfl
    exact ofNat_lt_ofNat_of_lt (pow_pos (by 

Proof state:
m n : ℕ
⊢ 0 < 2

Next tactic:
decide
theorem one_shiftLeft (n : ℕ) : 1 <<< (n : ℤ) = (2 ^ n : ℕ) :=
  congr_arg ((↑) : ℕ → ℤ) (by 

Proof state:
n : ℕ
⊢ Nat.shiftLeft' false 1 n = 2 ^ n

Next tactic:
simp [Nat.shiftLeft_eq]
@[simp]
theorem zero_shiftLeft : ∀ n : ℤ, 0 <<< n = 0
  | (n : ℕ) => congr_arg ((↑) : ℕ → ℤ) (by 

Proof state:
n : ℕ
⊢ Nat.shiftLeft' false 0 n = 0

Next tactic:
simp
@[simp]
theorem zero_shiftLeft : ∀ n : ℤ, 0 <<< n = 0
  | (n : ℕ) => congr_arg ((↑) : ℕ → ℤ) (by simp)
  | -[_+1] => congr_arg ((↑) : ℕ → ℤ) (by 

Proof state:
a✝ : ℕ
⊢ 0 >>> Nat.succ a✝ = 0

Next tactic:
simp
@[to_additive]
theorem colimitInvAux_eq_of_rel (x y : Σ j, F.obj j)
    (h : Types.FilteredColimit.Rel.{v, u} (F ⋙ forget GroupCat) x y) :
    colimitInvAux.{v, u} F x = colimitInvAux F y := by
  

Proof state:
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x y : (j : J) × ↑(F.obj j)
h : Types.FilteredColimit.Rel (F ⋙ forget GroupCat) x y
⊢ colimitInvAux F x = colimitInvAux F y

Next tactic:
apply G.mk_eq
@[to_additive]
theorem colimitInvAux_eq_of_rel (x y : Σ j, F.obj j)
    (h : Types.FilteredColimit.Rel.{v, u} (F ⋙ forget GroupCat) x y) :
    colimitInvAux.{v, u} F x = colimitInvAux F y := by
  apply G.mk_eq
  

Proof state:
case h
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x y : (j : J) × ↑(F.obj j)
h : Types.FilteredColimit.Rel (F ⋙ forget GroupCat) x y
⊢ ∃ k f g, (F.map f) { fst := x.fst, snd := x.snd⁻¹ }.snd = (F.map g) { fst := y.fst, snd := y.snd⁻¹ }.snd

Next tactic:
obtain ⟨k, f, g, hfg⟩ := h
@[to_additive]
theorem colimitInvAux_eq_of_rel (x y : Σ j, F.obj j)
    (h : Types.FilteredColimit.Rel.{v, u} (F ⋙ forget GroupCat) x y) :
    colimitInvAux.{v, u} F x = colimitInvAux F y := by
  apply G.mk_eq
  obtain ⟨k, f, g, hfg⟩ := h
  

Proof state:
case h.intro.intro.intro
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x y : (j : J) × ↑(F.obj j)
k : J
f : x.fst ⟶ k
g : y.fst ⟶ k
hfg : (F ⋙ forget GroupCat).map f x.snd = (F ⋙ forget GroupCat).map g y.snd
⊢ ∃ k f g, (F.map f) { fst := x.fst, snd := x.snd⁻¹ }.snd = (F.map g) { fst := y.fst, snd := y.snd⁻¹ }.snd

Next tactic:
use k, f, g
@[to_additive]
theorem colimitInvAux_eq_of_rel (x y : Σ j, F.obj j)
    (h : Types.FilteredColimit.Rel.{v, u} (F ⋙ forget GroupCat) x y) :
    colimitInvAux.{v, u} F x = colimitInvAux F y := by
  apply G.mk_eq
  obtain ⟨k, f, g, hfg⟩ := h
  use k, f, g
  

Proof state:
case h
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x y : (j : J) × ↑(F.obj j)
k : J
f : x.fst ⟶ k
g : y.fst ⟶ k
hfg : (F ⋙ forget GroupCat).map f x.snd = (F ⋙ forget GroupCat).map g y.snd
⊢ (F.map f) { fst := x.fst, snd := x.snd⁻¹ }.snd = (F.map g) { fst := y.fst, snd := y.snd⁻¹ }.snd

Next tactic:
rw [MonoidHom.map_inv, MonoidHom.map_inv, inv_inj]
@[to_additive]
theorem colimitInvAux_eq_of_rel (x y : Σ j, F.obj j)
    (h : Types.FilteredColimit.Rel.{v, u} (F ⋙ forget GroupCat) x y) :
    colimitInvAux.{v, u} F x = colimitInvAux F y := by
  apply G.mk_eq
  obtain ⟨k, f, g, hfg⟩ := h
  use k, f, g
  rw [MonoidHom.map_inv, MonoidHom.map_inv, inv_inj]
  

Proof state:
case h
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x y : (j : J) × ↑(F.obj j)
k : J
f : x.fst ⟶ k
g : y.fst ⟶ k
hfg : (F ⋙ forget GroupCat).map f x.snd = (F ⋙ forget GroupCat).map g y.snd
⊢ (F.map f) x.snd = (F.map g) y.snd

Next tactic:
exact hfg
/-- Taking inverses in the colimit. See also `colimitInvAux`. -/
@[to_additive "Negation in the colimit. See also `colimitNegAux`."]
instance colimitInv : Inv (G.{v, u} F) where
  inv x := by
    

Proof state:
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x : ↑(G F)
⊢ ↑(G F)

Next tactic:
refine' Quot.lift (colimitInvAux.{v, u} F) _ x
/-- Taking inverses in the colimit. See also `colimitInvAux`. -/
@[to_additive "Negation in the colimit. See also `colimitNegAux`."]
instance colimitInv : Inv (G.{v, u} F) where
  inv x := by
    refine' Quot.lift (colimitInvAux.{v, u} F) _ x
    

Proof state:
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x : ↑(G F)
⊢ ∀ (a b : (j : J) × ↑(F.obj j)),
    Types.Quot.Rel ((F ⋙ forget₂ GroupCat MonCat) ⋙ forget MonCat) a b → colimitInvAux F a = colimitInvAux F b

Next tactic:
intro x y h
/-- Taking inverses in the colimit. See also `colimitInvAux`. -/
@[to_additive "Negation in the colimit. See also `colimitNegAux`."]
instance colimitInv : Inv (G.{v, u} F) where
  inv x := by
    refine' Quot.lift (colimitInvAux.{v, u} F) _ x
    intro x y h
    

Proof state:
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x✝ : ↑(G F)
x y : (j : J) × ↑(F.obj j)
h : Types.Quot.Rel ((F ⋙ forget₂ GroupCat MonCat) ⋙ forget MonCat) x y
⊢ colimitInvAux F x = colimitInvAux F y

Next tactic:
apply colimitInvAux_eq_of_rel
/-- Taking inverses in the colimit. See also `colimitInvAux`. -/
@[to_additive "Negation in the colimit. See also `colimitNegAux`."]
instance colimitInv : Inv (G.{v, u} F) where
  inv x := by
    refine' Quot.lift (colimitInvAux.{v, u} F) _ x
    intro x y h
    apply colimitInvAux_eq_of_rel
    

Proof state:
case h
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x✝ : ↑(G F)
x y : (j : J) × ↑(F.obj j)
h : Types.Quot.Rel ((F ⋙ forget₂ GroupCat MonCat) ⋙ forget MonCat) x y
⊢ Types.FilteredColimit.Rel (F ⋙ forget GroupCat) x y

Next tactic:
apply Types.FilteredColimit.rel_of_quot_rel
/-- Taking inverses in the colimit. See also `colimitInvAux`. -/
@[to_additive "Negation in the colimit. See also `colimitNegAux`."]
instance colimitInv : Inv (G.{v, u} F) where
  inv x := by
    refine' Quot.lift (colimitInvAux.{v, u} F) _ x
    intro x y h
    apply colimitInvAux_eq_of_rel
    apply Types.FilteredColimit.rel_of_quot_rel
    

Proof state:
case h.a
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
x✝ : ↑(G F)
x y : (j : J) × ↑(F.obj j)
h : Types.Quot.Rel ((F ⋙ forget₂ GroupCat MonCat) ⋙ forget MonCat) x y
⊢ Types.Quot.Rel (F ⋙ forget GroupCat) x y

Next tactic:
exact h
@[to_additive]
noncomputable instance colimitGroup : Group (G.{v, u} F) :=
  { colimitInv.{v, u} F, (G.{v, u} F).str with
    mul_left_inv := fun x => by
      

Proof state:
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
src✝¹ : Inv ↑(G F) := colimitInv F
src✝ : Monoid ↑(G F) := (G F).str
x : ↑(G F)
⊢ x⁻¹ * x = 1

Next tactic:
refine Quot.inductionOn x ?_
@[to_additive]
noncomputable instance colimitGroup : Group (G.{v, u} F) :=
  { colimitInv.{v, u} F, (G.{v, u} F).str with
    mul_left_inv := fun x => by
      refine Quot.inductionOn x ?_; 

Proof state:
J : Type v
inst✝¹ : SmallCategory J
inst✝ : IsFiltered J
F : J ⥤ GroupCat
src✝¹ : Inv ↑(G F) := colimitInv F
src✝ : Monoid ↑(G F) := (G F).str
x : ↑(G F)
⊢ ∀ (a : (j : J) × ((F ⋙ forget₂ GroupCat MonCat) ⋙ forget MonCat).obj j),
    (Quot.mk (Types.Quot.Rel ((F ⋙ forget₂ GroupCat MonCat) ⋙ forget MonCat)) a)⁻¹ *
        Quot.mk (Types.Quot.Rel ((F ⋙ forget₂ GroupCat MonCat) ⋙ forget MonCat)) a =
      1

Next tactic:
clear x