/-
Copyright (c) 2020 Yury Kudryashov. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Yury Kudryashov

! This file was ported from Lean 3 source module linear_algebra.affine_space.midpoint_zero
! leanprover-community/mathlib commit 78261225eb5cedc61c5c74ecb44e5b385d13b733
! Please do not edit these lines, except to modify the commit id
! if you have ported upstream changes.
-/
import Mathbin.Algebra.CharP.Invertible
import Mathbin.LinearAlgebra.AffineSpace.Midpoint

/-!
# Midpoint of a segment for characteristic zero

We collect lemmas that require that the underlying ring has characteristic zero.

## Tags

midpoint
-/

open AffineMap AffineEquiv

/- warning: line_map_inv_two -> lineMap_inv_two is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {V : Type.{u2}} {P : Type.{u3}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u1, u2} R V (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1)) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u3} P (coeFn.{max (succ u1) (succ u2) (succ u3), max (succ u1) (succ u3)} (AffineMap.{u1, u1, u1, u2, u3} R R R V P (DivisionRing.toRing.{u1} R _inst_1) (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (addGroupIsAddTorsor.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))) _inst_3 _inst_4 _inst_5) (fun (_x : AffineMap.{u1, u1, u1, u2, u3} R R R V P (DivisionRing.toRing.{u1} R _inst_1) (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (addGroupIsAddTorsor.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))) _inst_3 _inst_4 _inst_5) => R -> P) (AffineMap.hasCoeToFun.{u1, u1, u1, u2, u3} R R R V P (DivisionRing.toRing.{u1} R _inst_1) (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (addGroupIsAddTorsor.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))) _inst_3 _inst_4 _inst_5) (AffineMap.lineMap.{u1, u2, u3} R V P (DivisionRing.toRing.{u1} R _inst_1) _inst_3 _inst_4 _inst_5 a b) (Inv.inv.{u1} R (DivInvMonoid.toHasInv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1)) (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))))))) (midpoint.{u1, u2, u3} R V P (DivisionRing.toRing.{u1} R _inst_1) (invertibleTwo.{u1} R _inst_1 _inst_2) _inst_3 _inst_4 _inst_5 a b)
but is expected to have type
  forall {R : Type.{u3}} {V : Type.{u2}} {P : Type.{u1}} [_inst_1 : DivisionRing.{u3} R] [_inst_2 : CharZero.{u3} R (AddGroupWithOne.toAddMonoidWithOne.{u3} R (Ring.toAddGroupWithOne.{u3} R (DivisionRing.toRing.{u3} R _inst_1)))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u3, u2} R V (DivisionSemiring.toSemiring.{u3} R (DivisionRing.toDivisionSemiring.{u3} R _inst_1)) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u1} ((fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : R) => P) (Inv.inv.{u3} R (DivisionRing.toInv.{u3} R _inst_1) (OfNat.ofNat.{u3} R 2 (instOfNat.{u3} R 2 (NonAssocRing.toNatCast.{u3} R (Ring.toNonAssocRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) (FunLike.coe.{max (max (succ u3) (succ u2)) (succ u1), succ u3, succ u1} (AffineMap.{u3, u3, u3, u2, u1} R R R V P (DivisionRing.toRing.{u3} R _inst_1) (Ring.toAddCommGroup.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (AffineMap.instModuleToSemiringToAddCommMonoidToNonUnitalNonAssocSemiringToNonUnitalNonAssocRingToNonUnitalRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (addGroupIsAddTorsor.{u3} R (AddGroupWithOne.toAddGroup.{u3} R (Ring.toAddGroupWithOne.{u3} R (DivisionRing.toRing.{u3} R _inst_1)))) _inst_3 _inst_4 _inst_5) R (fun (_x : R) => (fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : R) => P) _x) (AffineMap.funLike.{u3, u3, u3, u2, u1} R R R V P (DivisionRing.toRing.{u3} R _inst_1) (Ring.toAddCommGroup.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (AffineMap.instModuleToSemiringToAddCommMonoidToNonUnitalNonAssocSemiringToNonUnitalNonAssocRingToNonUnitalRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (addGroupIsAddTorsor.{u3} R (AddGroupWithOne.toAddGroup.{u3} R (Ring.toAddGroupWithOne.{u3} R (DivisionRing.toRing.{u3} R _inst_1)))) _inst_3 _inst_4 _inst_5) (AffineMap.lineMap.{u3, u2, u1} R V P (DivisionRing.toRing.{u3} R _inst_1) _inst_3 _inst_4 _inst_5 a b) (Inv.inv.{u3} R (DivisionRing.toInv.{u3} R _inst_1) (OfNat.ofNat.{u3} R 2 (instOfNat.{u3} R 2 (NonAssocRing.toNatCast.{u3} R (Ring.toNonAssocRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) (midpoint.{u3, u2, u1} R V P (DivisionRing.toRing.{u3} R _inst_1) (invertibleTwo.{u3} R _inst_1 _inst_2) _inst_3 _inst_4 _inst_5 a b)
Case conversion may be inaccurate. Consider using '#align line_map_inv_two lineMap_inv_twoₓ'. -/
theorem lineMap_inv_two {R : Type _} {V P : Type _} [DivisionRing R] [CharZero R] [AddCommGroup V]
    [Module R V] [AddTorsor V P] (a b : P) : lineMap a b (2⁻¹ : R) = midpoint R a b :=
  rfl
#align line_map_inv_two lineMap_inv_two

/- warning: line_map_one_half -> lineMap_one_half is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {V : Type.{u2}} {P : Type.{u3}} [_inst_1 : DivisionRing.{u1} R] [_inst_2 : CharZero.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u1, u2} R V (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1)) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u3} P (coeFn.{max (succ u1) (succ u2) (succ u3), max (succ u1) (succ u3)} (AffineMap.{u1, u1, u1, u2, u3} R R R V P (DivisionRing.toRing.{u1} R _inst_1) (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (addGroupIsAddTorsor.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))) _inst_3 _inst_4 _inst_5) (fun (_x : AffineMap.{u1, u1, u1, u2, u3} R R R V P (DivisionRing.toRing.{u1} R _inst_1) (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (addGroupIsAddTorsor.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))) _inst_3 _inst_4 _inst_5) => R -> P) (AffineMap.hasCoeToFun.{u1, u1, u1, u2, u3} R R R V P (DivisionRing.toRing.{u1} R _inst_1) (NonUnitalNonAssocRing.toAddCommGroup.{u1} R (NonAssocRing.toNonUnitalNonAssocRing.{u1} R (Ring.toNonAssocRing.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))) (Semiring.toModule.{u1} R (Ring.toSemiring.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (addGroupIsAddTorsor.{u1} R (AddGroupWithOne.toAddGroup.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))) _inst_3 _inst_4 _inst_5) (AffineMap.lineMap.{u1, u2, u3} R V P (DivisionRing.toRing.{u1} R _inst_1) _inst_3 _inst_4 _inst_5 a b) (HDiv.hDiv.{u1, u1, u1} R R R (instHDiv.{u1} R (DivInvMonoid.toHasDiv.{u1} R (DivisionRing.toDivInvMonoid.{u1} R _inst_1))) (OfNat.ofNat.{u1} R 1 (OfNat.mk.{u1} R 1 (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1)))))))) (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (DivisionRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (DivisionRing.toRing.{u1} R _inst_1))))))))))) (midpoint.{u1, u2, u3} R V P (DivisionRing.toRing.{u1} R _inst_1) (invertibleTwo.{u1} R _inst_1 _inst_2) _inst_3 _inst_4 _inst_5 a b)
but is expected to have type
  forall {R : Type.{u3}} {V : Type.{u2}} {P : Type.{u1}} [_inst_1 : DivisionRing.{u3} R] [_inst_2 : CharZero.{u3} R (AddGroupWithOne.toAddMonoidWithOne.{u3} R (Ring.toAddGroupWithOne.{u3} R (DivisionRing.toRing.{u3} R _inst_1)))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u3, u2} R V (DivisionSemiring.toSemiring.{u3} R (DivisionRing.toDivisionSemiring.{u3} R _inst_1)) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u1} ((fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : R) => P) (HDiv.hDiv.{u3, u3, u3} R R R (instHDiv.{u3} R (DivisionRing.toDiv.{u3} R _inst_1)) (OfNat.ofNat.{u3} R 1 (One.toOfNat1.{u3} R (NonAssocRing.toOne.{u3} R (Ring.toNonAssocRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1))))) (OfNat.ofNat.{u3} R 2 (instOfNat.{u3} R 2 (NonAssocRing.toNatCast.{u3} R (Ring.toNonAssocRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) (FunLike.coe.{max (max (succ u3) (succ u2)) (succ u1), succ u3, succ u1} (AffineMap.{u3, u3, u3, u2, u1} R R R V P (DivisionRing.toRing.{u3} R _inst_1) (Ring.toAddCommGroup.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (AffineMap.instModuleToSemiringToAddCommMonoidToNonUnitalNonAssocSemiringToNonUnitalNonAssocRingToNonUnitalRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (addGroupIsAddTorsor.{u3} R (AddGroupWithOne.toAddGroup.{u3} R (Ring.toAddGroupWithOne.{u3} R (DivisionRing.toRing.{u3} R _inst_1)))) _inst_3 _inst_4 _inst_5) R (fun (_x : R) => (fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : R) => P) _x) (AffineMap.funLike.{u3, u3, u3, u2, u1} R R R V P (DivisionRing.toRing.{u3} R _inst_1) (Ring.toAddCommGroup.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (AffineMap.instModuleToSemiringToAddCommMonoidToNonUnitalNonAssocSemiringToNonUnitalNonAssocRingToNonUnitalRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1)) (addGroupIsAddTorsor.{u3} R (AddGroupWithOne.toAddGroup.{u3} R (Ring.toAddGroupWithOne.{u3} R (DivisionRing.toRing.{u3} R _inst_1)))) _inst_3 _inst_4 _inst_5) (AffineMap.lineMap.{u3, u2, u1} R V P (DivisionRing.toRing.{u3} R _inst_1) _inst_3 _inst_4 _inst_5 a b) (HDiv.hDiv.{u3, u3, u3} R R R (instHDiv.{u3} R (DivisionRing.toDiv.{u3} R _inst_1)) (OfNat.ofNat.{u3} R 1 (One.toOfNat1.{u3} R (NonAssocRing.toOne.{u3} R (Ring.toNonAssocRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1))))) (OfNat.ofNat.{u3} R 2 (instOfNat.{u3} R 2 (NonAssocRing.toNatCast.{u3} R (Ring.toNonAssocRing.{u3} R (DivisionRing.toRing.{u3} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) (midpoint.{u3, u2, u1} R V P (DivisionRing.toRing.{u3} R _inst_1) (invertibleTwo.{u3} R _inst_1 _inst_2) _inst_3 _inst_4 _inst_5 a b)
Case conversion may be inaccurate. Consider using '#align line_map_one_half lineMap_one_halfₓ'. -/
theorem lineMap_one_half {R : Type _} {V P : Type _} [DivisionRing R] [CharZero R] [AddCommGroup V]
    [Module R V] [AddTorsor V P] (a b : P) : lineMap a b (1 / 2 : R) = midpoint R a b := by
  rw [one_div, lineMap_inv_two]
#align line_map_one_half lineMap_one_half

/- warning: homothety_inv_of_two -> homothety_invOf_two is a dubious translation:
lean 3 declaration is
  forall {R : Type.{u1}} {V : Type.{u2}} {P : Type.{u3}} [_inst_1 : CommRing.{u1} R] [_inst_2 : Invertible.{u1} R (Distrib.toHasMul.{u1} R (Ring.toDistrib.{u1} R (CommRing.toRing.{u1} R _inst_1))) (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (CommRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1)))))))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u1, u2} R V (Ring.toSemiring.{u1} R (CommRing.toRing.{u1} R _inst_1)) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u3} P (coeFn.{max (succ u2) (succ u3), succ u3} (AffineMap.{u1, u2, u3, u2, u3} R V P V P (CommRing.toRing.{u1} R _inst_1) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (fun (_x : AffineMap.{u1, u2, u3, u2, u3} R V P V P (CommRing.toRing.{u1} R _inst_1) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) => P -> P) (AffineMap.hasCoeToFun.{u1, u2, u3, u2, u3} R V P V P (CommRing.toRing.{u1} R _inst_1) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (AffineMap.homothety.{u1, u2, u3} R V P _inst_1 _inst_3 _inst_5 _inst_4 a (Invertible.invOf.{u1} R (Distrib.toHasMul.{u1} R (Ring.toDistrib.{u1} R (CommRing.toRing.{u1} R _inst_1))) (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1))))) (OfNat.ofNat.{u1} R 2 (OfNat.mk.{u1} R 2 (bit0.{u1} R (Distrib.toHasAdd.{u1} R (Ring.toDistrib.{u1} R (CommRing.toRing.{u1} R _inst_1))) (One.one.{u1} R (AddMonoidWithOne.toOne.{u1} R (AddGroupWithOne.toAddMonoidWithOne.{u1} R (AddCommGroupWithOne.toAddGroupWithOne.{u1} R (Ring.toAddCommGroupWithOne.{u1} R (CommRing.toRing.{u1} R _inst_1))))))))) _inst_2)) b) (midpoint.{u1, u2, u3} R V P (CommRing.toRing.{u1} R _inst_1) _inst_2 _inst_3 _inst_4 _inst_5 a b)
but is expected to have type
  forall {R : Type.{u3}} {V : Type.{u2}} {P : Type.{u1}} [_inst_1 : CommRing.{u3} R] [_inst_2 : Invertible.{u3} R (NonUnitalNonAssocRing.toMul.{u3} R (NonAssocRing.toNonUnitalNonAssocRing.{u3} R (Ring.toNonAssocRing.{u3} R (CommRing.toRing.{u3} R _inst_1)))) (NonAssocRing.toOne.{u3} R (Ring.toNonAssocRing.{u3} R (CommRing.toRing.{u3} R _inst_1))) (OfNat.ofNat.{u3} R 2 (instOfNat.{u3} R 2 (NonAssocRing.toNatCast.{u3} R (Ring.toNonAssocRing.{u3} R (CommRing.toRing.{u3} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u3, u2} R V (Ring.toSemiring.{u3} R (CommRing.toRing.{u3} R _inst_1)) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u1} ((fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : P) => P) b) (FunLike.coe.{max (succ u2) (succ u1), succ u1, succ u1} (AffineMap.{u3, u2, u1, u2, u1} R V P V P (CommRing.toRing.{u3} R _inst_1) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) P (fun (_x : P) => (fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : P) => P) _x) (AffineMap.funLike.{u3, u2, u1, u2, u1} R V P V P (CommRing.toRing.{u3} R _inst_1) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (AffineMap.homothety.{u3, u2, u1} R V P _inst_1 _inst_3 _inst_5 _inst_4 a (Invertible.invOf.{u3} R (NonUnitalNonAssocRing.toMul.{u3} R (NonAssocRing.toNonUnitalNonAssocRing.{u3} R (Ring.toNonAssocRing.{u3} R (CommRing.toRing.{u3} R _inst_1)))) (NonAssocRing.toOne.{u3} R (Ring.toNonAssocRing.{u3} R (CommRing.toRing.{u3} R _inst_1))) (OfNat.ofNat.{u3} R 2 (instOfNat.{u3} R 2 (NonAssocRing.toNatCast.{u3} R (Ring.toNonAssocRing.{u3} R (CommRing.toRing.{u3} R _inst_1))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))) _inst_2)) b) (midpoint.{u3, u2, u1} R V P (CommRing.toRing.{u3} R _inst_1) _inst_2 _inst_3 _inst_4 _inst_5 a b)
Case conversion may be inaccurate. Consider using '#align homothety_inv_of_two homothety_invOf_twoₓ'. -/
theorem homothety_invOf_two {R : Type _} {V P : Type _} [CommRing R] [Invertible (2 : R)]
    [AddCommGroup V] [Module R V] [AddTorsor V P] (a b : P) :
    homothety a (⅟ 2 : R) b = midpoint R a b :=
  rfl
#align homothety_inv_of_two homothety_invOf_two

/- warning: homothety_inv_two -> homothety_inv_two is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {V : Type.{u2}} {P : Type.{u3}} [_inst_1 : Field.{u1} k] [_inst_2 : CharZero.{u1} k (AddGroupWithOne.toAddMonoidWithOne.{u1} k (AddCommGroupWithOne.toAddGroupWithOne.{u1} k (Ring.toAddCommGroupWithOne.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u1, u2} k V (Ring.toSemiring.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1))) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u3} P (coeFn.{max (succ u2) (succ u3), succ u3} (AffineMap.{u1, u2, u3, u2, u3} k V P V P (CommRing.toRing.{u1} k (Field.toCommRing.{u1} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (fun (_x : AffineMap.{u1, u2, u3, u2, u3} k V P V P (CommRing.toRing.{u1} k (Field.toCommRing.{u1} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) => P -> P) (AffineMap.hasCoeToFun.{u1, u2, u3, u2, u3} k V P V P (CommRing.toRing.{u1} k (Field.toCommRing.{u1} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (AffineMap.homothety.{u1, u2, u3} k V P (Field.toCommRing.{u1} k _inst_1) _inst_3 _inst_5 _inst_4 a (Inv.inv.{u1} k (DivInvMonoid.toHasInv.{u1} k (DivisionRing.toDivInvMonoid.{u1} k (Field.toDivisionRing.{u1} k _inst_1))) (OfNat.ofNat.{u1} k 2 (OfNat.mk.{u1} k 2 (bit0.{u1} k (Distrib.toHasAdd.{u1} k (Ring.toDistrib.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))) (One.one.{u1} k (AddMonoidWithOne.toOne.{u1} k (AddGroupWithOne.toAddMonoidWithOne.{u1} k (AddCommGroupWithOne.toAddGroupWithOne.{u1} k (Ring.toAddCommGroupWithOne.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))))))))))) b) (midpoint.{u1, u2, u3} k V P (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)) (invertibleTwo.{u1} k (Field.toDivisionRing.{u1} k _inst_1) _inst_2) _inst_3 _inst_4 _inst_5 a b)
but is expected to have type
  forall {k : Type.{u3}} {V : Type.{u2}} {P : Type.{u1}} [_inst_1 : Field.{u3} k] [_inst_2 : CharZero.{u3} k (AddGroupWithOne.toAddMonoidWithOne.{u3} k (Ring.toAddGroupWithOne.{u3} k (DivisionRing.toRing.{u3} k (Field.toDivisionRing.{u3} k _inst_1))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u3, u2} k V (DivisionSemiring.toSemiring.{u3} k (Semifield.toDivisionSemiring.{u3} k (Field.toSemifield.{u3} k _inst_1))) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u1} ((fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : P) => P) b) (FunLike.coe.{max (succ u2) (succ u1), succ u1, succ u1} (AffineMap.{u3, u2, u1, u2, u1} k V P V P (CommRing.toRing.{u3} k (Field.toCommRing.{u3} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) P (fun (_x : P) => (fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : P) => P) _x) (AffineMap.funLike.{u3, u2, u1, u2, u1} k V P V P (CommRing.toRing.{u3} k (Field.toCommRing.{u3} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (AffineMap.homothety.{u3, u2, u1} k V P (Field.toCommRing.{u3} k _inst_1) _inst_3 _inst_5 _inst_4 a (Inv.inv.{u3} k (Field.toInv.{u3} k _inst_1) (OfNat.ofNat.{u3} k 2 (instOfNat.{u3} k 2 (NonAssocRing.toNatCast.{u3} k (Ring.toNonAssocRing.{u3} k (DivisionRing.toRing.{u3} k (Field.toDivisionRing.{u3} k _inst_1)))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) b) (midpoint.{u3, u2, u1} k V P (DivisionRing.toRing.{u3} k (Field.toDivisionRing.{u3} k _inst_1)) (invertibleTwo.{u3} k (Field.toDivisionRing.{u3} k _inst_1) _inst_2) _inst_3 _inst_4 _inst_5 a b)
Case conversion may be inaccurate. Consider using '#align homothety_inv_two homothety_inv_twoₓ'. -/
theorem homothety_inv_two {k : Type _} {V P : Type _} [Field k] [CharZero k] [AddCommGroup V]
    [Module k V] [AddTorsor V P] (a b : P) : homothety a (2⁻¹ : k) b = midpoint k a b :=
  rfl
#align homothety_inv_two homothety_inv_two

/- warning: homothety_one_half -> homothety_one_half is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {V : Type.{u2}} {P : Type.{u3}} [_inst_1 : Field.{u1} k] [_inst_2 : CharZero.{u1} k (AddGroupWithOne.toAddMonoidWithOne.{u1} k (AddCommGroupWithOne.toAddGroupWithOne.{u1} k (Ring.toAddCommGroupWithOne.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u1, u2} k V (Ring.toSemiring.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1))) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u3} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u3} P (coeFn.{max (succ u2) (succ u3), succ u3} (AffineMap.{u1, u2, u3, u2, u3} k V P V P (CommRing.toRing.{u1} k (Field.toCommRing.{u1} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (fun (_x : AffineMap.{u1, u2, u3, u2, u3} k V P V P (CommRing.toRing.{u1} k (Field.toCommRing.{u1} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) => P -> P) (AffineMap.hasCoeToFun.{u1, u2, u3, u2, u3} k V P V P (CommRing.toRing.{u1} k (Field.toCommRing.{u1} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (AffineMap.homothety.{u1, u2, u3} k V P (Field.toCommRing.{u1} k _inst_1) _inst_3 _inst_5 _inst_4 a (HDiv.hDiv.{u1, u1, u1} k k k (instHDiv.{u1} k (DivInvMonoid.toHasDiv.{u1} k (DivisionRing.toDivInvMonoid.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))) (OfNat.ofNat.{u1} k 1 (OfNat.mk.{u1} k 1 (One.one.{u1} k (AddMonoidWithOne.toOne.{u1} k (AddGroupWithOne.toAddMonoidWithOne.{u1} k (AddCommGroupWithOne.toAddGroupWithOne.{u1} k (Ring.toAddCommGroupWithOne.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1))))))))) (OfNat.ofNat.{u1} k 2 (OfNat.mk.{u1} k 2 (bit0.{u1} k (Distrib.toHasAdd.{u1} k (Ring.toDistrib.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))) (One.one.{u1} k (AddMonoidWithOne.toOne.{u1} k (AddGroupWithOne.toAddMonoidWithOne.{u1} k (AddCommGroupWithOne.toAddGroupWithOne.{u1} k (Ring.toAddCommGroupWithOne.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))))))))))) b) (midpoint.{u1, u2, u3} k V P (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)) (invertibleTwo.{u1} k (Field.toDivisionRing.{u1} k _inst_1) _inst_2) _inst_3 _inst_4 _inst_5 a b)
but is expected to have type
  forall {k : Type.{u3}} {V : Type.{u2}} {P : Type.{u1}} [_inst_1 : Field.{u3} k] [_inst_2 : CharZero.{u3} k (AddGroupWithOne.toAddMonoidWithOne.{u3} k (Ring.toAddGroupWithOne.{u3} k (DivisionRing.toRing.{u3} k (Field.toDivisionRing.{u3} k _inst_1))))] [_inst_3 : AddCommGroup.{u2} V] [_inst_4 : Module.{u3, u2} k V (DivisionSemiring.toSemiring.{u3} k (Semifield.toDivisionSemiring.{u3} k (Field.toSemifield.{u3} k _inst_1))) (AddCommGroup.toAddCommMonoid.{u2} V _inst_3)] [_inst_5 : AddTorsor.{u2, u1} V P (AddCommGroup.toAddGroup.{u2} V _inst_3)] (a : P) (b : P), Eq.{succ u1} ((fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : P) => P) b) (FunLike.coe.{max (succ u2) (succ u1), succ u1, succ u1} (AffineMap.{u3, u2, u1, u2, u1} k V P V P (CommRing.toRing.{u3} k (Field.toCommRing.{u3} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) P (fun (_x : P) => (fun (a._@.Mathlib.LinearAlgebra.AffineSpace.AffineMap._hyg.1004 : P) => P) _x) (AffineMap.funLike.{u3, u2, u1, u2, u1} k V P V P (CommRing.toRing.{u3} k (Field.toCommRing.{u3} k _inst_1)) _inst_3 _inst_4 _inst_5 _inst_3 _inst_4 _inst_5) (AffineMap.homothety.{u3, u2, u1} k V P (Field.toCommRing.{u3} k _inst_1) _inst_3 _inst_5 _inst_4 a (HDiv.hDiv.{u3, u3, u3} k k k (instHDiv.{u3} k (Field.toDiv.{u3} k _inst_1)) (OfNat.ofNat.{u3} k 1 (One.toOfNat1.{u3} k (NonAssocRing.toOne.{u3} k (Ring.toNonAssocRing.{u3} k (DivisionRing.toRing.{u3} k (Field.toDivisionRing.{u3} k _inst_1)))))) (OfNat.ofNat.{u3} k 2 (instOfNat.{u3} k 2 (NonAssocRing.toNatCast.{u3} k (Ring.toNonAssocRing.{u3} k (DivisionRing.toRing.{u3} k (Field.toDivisionRing.{u3} k _inst_1)))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0))))))) b) (midpoint.{u3, u2, u1} k V P (DivisionRing.toRing.{u3} k (Field.toDivisionRing.{u3} k _inst_1)) (invertibleTwo.{u3} k (Field.toDivisionRing.{u3} k _inst_1) _inst_2) _inst_3 _inst_4 _inst_5 a b)
Case conversion may be inaccurate. Consider using '#align homothety_one_half homothety_one_halfₓ'. -/
theorem homothety_one_half {k : Type _} {V P : Type _} [Field k] [CharZero k] [AddCommGroup V]
    [Module k V] [AddTorsor V P] (a b : P) : homothety a (1 / 2 : k) b = midpoint k a b := by
  rw [one_div, homothety_inv_two]
#align homothety_one_half homothety_one_half

/- warning: pi_midpoint_apply -> pi_midpoint_apply is a dubious translation:
lean 3 declaration is
  forall {k : Type.{u1}} {ι : Type.{u2}} {V : ι -> Type.{u3}} {P : ι -> Type.{u4}} [_inst_1 : Field.{u1} k] [_inst_2 : Invertible.{u1} k (Distrib.toHasMul.{u1} k (Ring.toDistrib.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))) (AddMonoidWithOne.toOne.{u1} k (AddGroupWithOne.toAddMonoidWithOne.{u1} k (AddCommGroupWithOne.toAddGroupWithOne.{u1} k (Ring.toAddCommGroupWithOne.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))))) (OfNat.ofNat.{u1} k 2 (OfNat.mk.{u1} k 2 (bit0.{u1} k (Distrib.toHasAdd.{u1} k (Ring.toDistrib.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)))) (One.one.{u1} k (AddMonoidWithOne.toOne.{u1} k (AddGroupWithOne.toAddMonoidWithOne.{u1} k (AddCommGroupWithOne.toAddGroupWithOne.{u1} k (Ring.toAddCommGroupWithOne.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1))))))))))] [_inst_3 : forall (i : ι), AddCommGroup.{u3} (V i)] [_inst_4 : forall (i : ι), Module.{u1, u3} k (V i) (Ring.toSemiring.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1))) (AddCommGroup.toAddCommMonoid.{u3} (V i) (_inst_3 i))] [_inst_5 : forall (i : ι), AddTorsor.{u3, u4} (V i) (P i) (AddCommGroup.toAddGroup.{u3} (V i) (_inst_3 i))] (f : forall (i : ι), P i) (g : forall (i : ι), P i) (i : ι), Eq.{succ u4} (P i) (midpoint.{u1, max u2 u3, max u2 u4} k (forall (i : ι), V i) (forall (i : ι), P i) (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)) _inst_2 (Pi.addCommGroup.{u2, u3} ι (fun (i : ι) => V i) (fun (i : ι) => _inst_3 i)) (Pi.module.{u2, u3, u1} ι (fun (i : ι) => V i) k (Ring.toSemiring.{u1} k (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1))) (fun (i : ι) => AddCommGroup.toAddCommMonoid.{u3} (V i) (_inst_3 i)) (fun (i : ι) => _inst_4 i)) (Pi.addTorsor.{u2, u3, u4} ι (fun (i : ι) => V i) (fun (i : ι) => AddCommGroup.toAddGroup.{u3} (V i) (_inst_3 i)) (fun (i : ι) => P i) (fun (i : ι) => _inst_5 i)) f g i) (midpoint.{u1, u3, u4} k (V i) (P i) (DivisionRing.toRing.{u1} k (Field.toDivisionRing.{u1} k _inst_1)) _inst_2 (_inst_3 i) (_inst_4 i) (_inst_5 i) (f i) (g i))
but is expected to have type
  forall {k : Type.{u4}} {ι : Type.{u3}} {V : ι -> Type.{u2}} {P : ι -> Type.{u1}} [_inst_1 : Field.{u4} k] [_inst_2 : Invertible.{u4} k (NonUnitalNonAssocRing.toMul.{u4} k (NonAssocRing.toNonUnitalNonAssocRing.{u4} k (Ring.toNonAssocRing.{u4} k (DivisionRing.toRing.{u4} k (Field.toDivisionRing.{u4} k _inst_1))))) (NonAssocRing.toOne.{u4} k (Ring.toNonAssocRing.{u4} k (DivisionRing.toRing.{u4} k (Field.toDivisionRing.{u4} k _inst_1)))) (OfNat.ofNat.{u4} k 2 (instOfNat.{u4} k 2 (NonAssocRing.toNatCast.{u4} k (Ring.toNonAssocRing.{u4} k (DivisionRing.toRing.{u4} k (Field.toDivisionRing.{u4} k _inst_1)))) (instAtLeastTwoHAddNatInstHAddInstAddNatOfNat (OfNat.ofNat.{0} Nat 0 (instOfNatNat 0)))))] [_inst_3 : forall (i : ι), AddCommGroup.{u2} (V i)] [_inst_4 : forall (i : ι), Module.{u4, u2} k (V i) (DivisionSemiring.toSemiring.{u4} k (Semifield.toDivisionSemiring.{u4} k (Field.toSemifield.{u4} k _inst_1))) (AddCommGroup.toAddCommMonoid.{u2} (V i) (_inst_3 i))] [_inst_5 : forall (i : ι), AddTorsor.{u2, u1} (V i) (P i) (AddCommGroup.toAddGroup.{u2} (V i) (_inst_3 i))] (f : forall (i : ι), P i) (g : forall (i : ι), P i) (i : ι), Eq.{succ u1} (P i) (midpoint.{u4, max u3 u2, max u3 u1} k (forall (i : ι), V i) (forall (i : ι), P i) (DivisionRing.toRing.{u4} k (Field.toDivisionRing.{u4} k _inst_1)) _inst_2 (Pi.addCommGroup.{u3, u2} ι (fun (i : ι) => V i) (fun (i : ι) => _inst_3 i)) (Pi.module.{u3, u2, u4} ι (fun (i : ι) => V i) k (Ring.toSemiring.{u4} k (DivisionRing.toRing.{u4} k (Field.toDivisionRing.{u4} k _inst_1))) (fun (i : ι) => AddCommGroup.toAddCommMonoid.{u2} (V i) (_inst_3 i)) (fun (i : ι) => _inst_4 i)) (AffineMap.instAddTorsorForAllForAllAddGroupToAddGroup.{u3, u2, u1} ι (fun (i : ι) => V i) (fun (i : ι) => P i) (fun (i : ι) => _inst_3 i) (fun (i : ι) => _inst_5 i)) f g i) (midpoint.{u4, u2, u1} k (V i) (P i) (DivisionRing.toRing.{u4} k (Field.toDivisionRing.{u4} k _inst_1)) _inst_2 (_inst_3 i) (_inst_4 i) (_inst_5 i) (f i) (g i))
Case conversion may be inaccurate. Consider using '#align pi_midpoint_apply pi_midpoint_applyₓ'. -/
@[simp]
theorem pi_midpoint_apply {k ι : Type _} {V : ∀ i : ι, Type _} {P : ∀ i : ι, Type _} [Field k]
    [Invertible (2 : k)] [∀ i, AddCommGroup (V i)] [∀ i, Module k (V i)]
    [∀ i, AddTorsor (V i) (P i)] (f g : ∀ i, P i) (i : ι) :
    midpoint k f g i = midpoint k (f i) (g i) :=
  rfl
#align pi_midpoint_apply pi_midpoint_apply


-- The rintro tactic is a combination of the intros tactic with rcases
-- to allow for destructuring patterns while introducing variables

-- See https://leanprover-community.github.io/mathlib_docs/tactics.html#rintro

import tactic

variables (P Q R : Prop)

-- For example, Here we prove with first intro and then cases.
example : P ∧ Q → Q ∧ P :=
begin
  intro h,
  cases h with hP hQ,
  split; assumption
end

-- Using rintro, we can combine the intro and cases on to one line
example : P ∧ Q → Q ∧ P :=
begin
  rintro ⟨hP, hQ⟩,
  split; assumption
end

-- In term mode, this can be written using λ
example : P ∧ Q → Q ∧ P :=
λ⟨hP, hQ⟩, ⟨hQ, hP⟩

-- Note the ⟨ ⟩ in the rintro can be nested
example : ((P ∧ Q) ∧ R) → (P ∧ Q ∧ R) :=
begin
  rintro ⟨⟨hP, hQ⟩, hR⟩,
  exact ⟨hP, hQ, hR⟩,
end

-- and this in term mode becomes
example : ((P ∧ Q) ∧ R) → (P ∧ Q ∧ R) :=
λ ⟨⟨hP, hQ⟩, hR⟩, ⟨hP, hQ, hR⟩

-- Note, when the cases causes two goals.
example : P ∨ Q  → Q ∨ P :=
begin
  intro h,
  cases h with hP hQ,
  -- here we now have two goals
  {
    -- goal is given hP : P, prove Q ∨ P
    right, exact hP
  },
  {
    -- here goal is given hQ : Q, prove P ∨ R
    left, exact hQ
  }
end

-- In this case you need to use ( | ) notation with rcases
example : P ∨ Q  → Q ∨ P :=
begin
  rintro (hP | hQ),
    right, exact hP,
  left, exact hQ
end

-- In term mode, this uses the definition of or as an inductive type
-- and constructs the required proof directly from the parts.
example : P ∨ Q  → Q ∨ P :=
  or.rec or.inr or.inl


import data.fin.basic
import data.fintype.basic
import data.list
import ..automata_typeclass

variables {Sigma : Type} [decidable_eq Sigma]

def union_lang (P Q : lang Sigma) : lang Sigma
:= λ w , P w ∨ Q w

def union_ε_nfa {Sigma : Type*} (A : ε_nfa Sigma) (B : ε_nfa Sigma) : ε_nfa Sigma :=
  {
    Q := A.Q ⊕ B.Q,
    finQ := @sum.fintype A.Q B.Q A.finQ B.finQ,
    decQ := @sum.decidable_eq A.Q A.decQ B.Q B.decQ,
    inits := λ q, sum.cases_on q A.inits B.inits,
    decI := begin
      assume a,
      letI dr := A.decI, letI ds := B.decI,
      cases a;
      tauto,
    end,
    final := λ q, sum.cases_on q A.final B.final,
    decF := begin
      assume a,
      letI dr := A.decF, letI ds := B.decF,
      cases a;
      tauto,
    end,
    δ := λ a x b, match a, b with
      | (sum.inl a), (sum.inl b) := A.δ a x b
      | (sum.inl a), (sum.inr b) := false
      | (sum.inr a), (sum.inl b) := false
      | (sum.inr a), (sum.inr b) := B.δ a x b
      end,
    decD := begin
      assume a,
      simp at *,
      dsimp [sigma.uncurry],
      cases a with ax b,
      cases ax with a x,
      cases a,
      {
        cases b,
        simp at *,
        exact A.decD ⟨⟨a, x⟩, b⟩,
        simp at *,
        exact is_false id,
      },
      {
        cases b,
        simp at *,
        exact is_false id,
        simp at *,
        exact B.decD ⟨⟨a, x⟩, b⟩,
      }
    end,
  }

lemma uniform_union : ∀ A B : ε_nfa Sigma, ∀ w : word Sigma, ∀ q0 q1 : A.Q ⊕ B.Q,
  ε_nfa_δ_star (union_ε_nfa A B) q0 w q1 → (sum.is_left q0 = sum.is_left q1) :=
begin
  assume A B w q0 q1,
  assume h,
  induction h,
  refl,
  rw← h_ih,
  cases h_q0 with aq0 bq0,
  cases h_q1 with aq1 bq1;
  simp,
  cases h_ᾰ,
  cases h_q1 with aq1 bq1,
  simp,
  cases h_ᾰ,
  simp,
  rw← h_ih,
  cases h_q0 with aq0 bq0,
  cases h_q1 with aq1 bq1;
  simp,
  cases h_ᾰ,
  cases h_q1 with aq1 bq1,
  simp,
  cases h_ᾰ,
  simp,
end

lemma left_union' : ∀ A B : ε_nfa Sigma, ∀ w : word Sigma, ∀ q0' q1' : A.Q,
  ε_nfa_δ_star A q0' w q1' → ε_nfa_δ_star (union_ε_nfa A B) (sum.inl q0') w (sum.inl q1') :=
begin
  assume A B w q0' q1' h,
  induction h,
  case ε_nfa_δ_star.empty : q
  {
    constructor,
  },
  case ε_nfa_δ_star.step : q0 q1 q2 x w h0 h1 ih
  {
    fconstructor,
    exact (sum.inl q1),
    exact h0,
    exact ih,
  },
  case ε_nfa_δ_star.epsilon : q0 q1 q2 w h0 h1 ih
  {
    fconstructor,
    exact (sum.inl q1),
    exact h0,
    exact ih,
  }
end

lemma right_union' : ∀ A B : ε_nfa Sigma, ∀ w : word Sigma, ∀ q0' q1' : B.Q,
  ε_nfa_δ_star B q0' w q1' → ε_nfa_δ_star (union_ε_nfa A B) (sum.inr q0') w (sum.inr q1') :=
begin
  assume A B w q0' q1' h,
  induction h,
  case ε_nfa_δ_star.empty : q
  {
    constructor,
  },
  case ε_nfa_δ_star.step : q0 q1 q2 x w h0 h1 ih
  {
    fconstructor,
    exact (sum.inr q1),
    exact h0,
    exact ih,
  },
  case ε_nfa_δ_star.epsilon : q0 q1 q2 w h0 h1 ih
  {
    fconstructor,
    exact (sum.inr q1),
    exact h0,
    exact ih,
  }
end

lemma union_lem : ∀ A B : ε_nfa Sigma, ∀ w : word Sigma, ∀ q0 q1 : (union_ε_nfa A B).Q,
  ε_nfa_δ_star (union_ε_nfa A B) q0 w q1 ↔
    (∃ q0' q1' : A.Q, q0 = sum.inl q0' ∧ q1 = sum.inl q1' ∧ ε_nfa_δ_star A q0' w q1')
    ∨
    (∃ q0' q1' : B.Q, q0 = sum.inr q0' ∧ q1 = sum.inr q1' ∧ ε_nfa_δ_star B q0' w q1')
    :=
begin
  assume A B w q0 q1,
  constructor,
  {
    assume h,
    induction h,
    case ε_nfa_δ_star.empty : q
    {
      cases q,
      {
        left,
        existsi [q, q],
        have empty_construct: ε_nfa_δ_star A q list.nil q,
          constructor,
        exact and.intro (refl $ sum.inl q) (and.intro (refl $ sum.inl q) empty_construct),
      },
      {
        right,
        existsi [q, q],
        have empty_construct: ε_nfa_δ_star B q list.nil q,
          constructor,
        exact and.intro (refl $ sum.inr q) (and.intro (refl $ sum.inr q) empty_construct),
      }
    },
    case ε_nfa_δ_star.step : q00 q11 q22 x w h0 h1 ih
    {
      cases q00,
      {
        cases q11,
        {
          left,
          cases ih,
          {
            cases ih with q00' ih, cases ih with q11' ih,
            existsi [q00, q11'],
            constructor, refl,
            constructor, exact (and.elim_left (and.elim_right ih)),
            fconstructor,
            exact q11,
            exact h0,
            have eq : q11 = q00',
              injection (and.elim_left ih),
            rw eq,
            exact (and.elim_right (and.elim_right ih)),
          },
          {
            cases ih with q0' ih, cases ih with q1' ih,
            rw (and.elim_left ih) at h0,
            cases h0,
          },
        },
        {
          cases h0,
        }
      },
      {
        cases q11,
        {
          cases h0,
        },
        {
          right,
          cases ih,
          {
            cases ih with q0' ih, cases ih with q1' ih,
            rw (and.elim_left ih) at h0,
            cases h0,
          },
          {
            cases ih with q00' ih, cases ih with q11' ih,
            existsi [q00, q11'],
            constructor, refl,
            constructor, exact (and.elim_left (and.elim_right ih)),
            fconstructor,
            exact q11,
            exact h0,
            have eq : q11 = q00',
              injection (and.elim_left ih),
            rw eq,
            exact (and.elim_right (and.elim_right ih)),
          }
        }
      }
    },
    case ε_nfa_δ_star.epsilon : q00 q11 q22 w h0 h1 ih
    {
      cases q00,
      {
        cases q11,
        {
          left,
          cases ih,
          {
            cases ih with q00' ih, cases ih with q11' ih,
            existsi [q00, q11'],
            constructor, refl,
            constructor, exact (and.elim_left (and.elim_right ih)),
            fconstructor,
            exact q11,
            exact h0,
            have eq : q11 = q00',
              injection (and.elim_left ih),
            rw← eq at ih,
            exact (and.elim_right (and.elim_right ih)),
          },
          {
            cases ih with q0' ih, cases ih with q1' ih,
            rw (and.elim_left ih) at h0,
            cases h0,
          }
        },
        {
          cases h0,
        }
      },
      {
        cases q11,
        {
          cases h0,
        },
        {
          right,
          cases ih,
          {
            cases ih with q0' ih, cases ih with q1' ih,
            rw (and.elim_left ih) at h0,
            cases h0,
          },
          {
            cases ih with q00' ih, cases ih with q11' ih,
            existsi [q00, q11'],
            constructor, refl,
            constructor, exact (and.elim_left (and.elim_right ih)),
            fconstructor,
            exact q11,
            exact h0,
            have eq : q11 = q00',
              injection (and.elim_left ih),
            rw← eq at ih,
            exact (and.elim_right (and.elim_right ih)),
          }
        }
      }
    },
  },
  {
    assume h,
    cases h with hA hB,
    {
      cases hA with q0' hA, cases hA with q1' hA,
      cases hA with h0 hA, cases hA with h1 hA,
      have left_union: ε_nfa_δ_star (union_ε_nfa A B) (sum.inl q0') w (sum.inl q1'),
        apply (left_union' A B w q0' q1' hA),
      rw← h0 at left_union,
      rw← h1 at left_union,
      exact left_union,
    },
    {
      cases hB with q0' hB, cases hB with q1' hB,
      cases hB with h0 hB, cases hB with h1 hB,
      have right_union: ε_nfa_δ_star (union_ε_nfa A B) (sum.inr q0') w (sum.inr q1'),
        apply (right_union' A B w q0' q1' hB),
      rw← h0 at right_union,
      rw← h1 at right_union,
      exact right_union,
    }
  }
end

lemma left_union : ∀ A B : ε_nfa Sigma, ∀ w : word Sigma, ∀ q0 q1 : A.Q,
  ε_nfa_δ_star (union_ε_nfa A B) (sum.inl q0) w (sum.inl q1) ↔ ε_nfa_δ_star A q0 w q1 :=
begin
  assume A B w q0 q1,
  constructor,
  {
    assume h,
    have h1 := iff.mp (union_lem A B w (sum.inl q0) (sum.inl q1)),
    cases h1 h with h1 h1,
    {
      cases h1 with q0' h1, cases h1 with q1' h1,
      cases h1 with h1 h2, cases h2 with h2 h3,
      injections_and_clear,
      rw← h_1 at h3,
      rw← h_2 at h3,
      exact h3,
    },
    {
      cases h1 with q0' h1, cases h1 with q1' h1,
      cases (and.elim_left h1),
    }
  },
  {
    assume h,
    have h1 := iff.mpr (union_lem A B w (sum.inl q0) (sum.inl q1)),
    apply h1,
    left,
    existsi [q0, q1],
    constructor, refl,
    constructor, refl,
    exact h,
  },
end

lemma right_union : ∀ A B : ε_nfa Sigma, ∀ w : word Sigma, ∀ q0 q1 : B.Q,
   ε_nfa_δ_star (union_ε_nfa A B) (sum.inr q0) w (sum.inr q1) ↔ ε_nfa_δ_star B q0 w q1 :=
begin
  assume A B w q0 q1,
  constructor,
  {
    assume h,
    have h1 := iff.mp (union_lem A B w (sum.inr q0) (sum.inr q1)),
    cases h1 h with h1 h1,
    {
      cases h1 with q0' h1, cases h1 with q1' h1,
      cases (and.elim_left h1),
    },
    {
      cases h1 with q0' h1, cases h1 with q1' h1,
      cases h1 with h1 h2, cases h2 with h2 h3,
      injections_and_clear,
      rw← h_1 at h3,
      rw← h_2 at h3,
      exact h3,
    },
  },
  {
    assume h,
    have h1 := iff.mpr (union_lem A B w (sum.inr q0) (sum.inr q1)),
    apply h1,
    right,
    existsi [q0, q1],
    constructor, refl,
    constructor, refl,
    exact h,
  },
end

lemma union_ε_nfa_lang : ∀ A B : ε_nfa Sigma, ∀ w : word Sigma,
  ε_nfa_lang (union_ε_nfa A B) w ↔ union_lang (ε_nfa_lang A) (ε_nfa_lang B) w :=
begin
  assume A B w,
  constructor,
  {
    dsimp [ε_nfa_lang, union_lang],
    assume h,
    cases h with q0 h, cases h with q1 h,
    cases q0,
    {
      left,
      cases q1,
      existsi q0, existsi q1,
      constructor,
      exact (and.elim_left h),
      constructor,
      have g : ε_nfa_δ_star (union_ε_nfa A B) (sum.inl q0) w (sum.inl q1),
        exact (and.elim_left (and.elim_right h)),
      exact (left_union A B w q0 q1).mp g,
      exact (and.elim_right (and.elim_right h)),
      have f : false,
        have g : ε_nfa_δ_star (union_ε_nfa A B) (sum.inl q0) w (sum.inr q1),
          exact (and.elim_left (and.elim_right h)),
        have t := uniform_union A B w (sum.inl q0) (sum.inr q1) g,
          simp at t,
        exact t,
        cases f,
    },
    {
      right,
      cases q1,
      have g : ε_nfa_δ_star (union_ε_nfa A B) (sum.inr q0) w (sum.inl q1),
        exact (and.elim_left (and.elim_right h)),
      have t:= uniform_union A B w (sum.inr q0) (sum.inl q1) g,
        simp at t,
      cases t,
      existsi q0, existsi q1,
      constructor,
      exact (and.elim_left h),
      constructor,
      exact (right_union A B w q0 q1).mp (and.elim_left (and.elim_right h)),
      exact (and.elim_right (and.elim_right h)),
    }
  },
  {
    dsimp [union_lang, ε_nfa_lang],
    assume h,
    cases h,
    {
      cases h with q0 h, cases h with q1 h,
      existsi (sum.inl q0), existsi (sum.inl q1),
      constructor,
      exact (and.elim_left h),
      constructor,
      exact (left_union A B w q0 q1).mpr (and.elim_left (and.elim_right h)),
      exact (and.elim_right (and.elim_right h)),
    },
    {
      cases h with q0 h, cases h with q1 h,
      existsi (sum.inr q0), existsi (sum.inr q1),
      constructor,
      exact (and.elim_left h),
      constructor,
      exact (right_union A B w q0 q1).mpr (and.elim_left (and.elim_right h)),
      exact (and.elim_right (and.elim_right h)),
    }
  }
end


import data.real.basic

--OUTPUT 1
theorem nesbitt_inequality {a b c : ℝ} (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2) :=
begin
  have h1 : (a + b + c) / (b + c) + (a + b + c) / (a + c) + (a + b + c) / (a + b) ≥ 9 / 2, from by auto [add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_div, add_
end --Needs more than 2000 tokens!

/- FEW SHOT PROMPTS TO CODEX(START)
/--`theorem`
Power Set is Closed under Intersection
Let $S$ be a set.

Let $\powerset S$ be the power set of $S$.

Then:
:$\forall A, B \in \powerset S: A \cap B \in \powerset S$
`proof`
Let $A, B \in \powerset S$.

Then by the definition of power set, $A \subseteq S$ and $B \subseteq S$.

From Intersection is Subset we have that $A \cap B \subseteq A$.

It follows from Subset Relation is Transitive that $A \cap B \subseteq S$.

Thus $A \cap B \in \powerset S$ and closure is proved.
{{qed}}
-/
theorem power_set_intersection_closed {α : Type*} (S : set α) : ∀ A B ∈ 𝒫 S, (A ∩ B) ∈ 𝒫 S :=
begin
  assume (A : set α) (hA : A ∈ 𝒫 S) (B : set α) (hB : B ∈ 𝒫 S),
  have h1 : (A ⊆ S) ∧ (B ⊆ S), from by auto [set.subset_of_mem_powerset, set.subset_of_mem_powerset],
  have h2 : (A ∩ B) ⊆ A, from by auto [set.inter_subset_left],
  have h3 : (A ∩ B) ⊆ S, from by auto [set.subset.trans],
  show (A ∩ B) ∈  𝒫 S, from by auto [set.mem_powerset],
end

/--`theorem`
Square of Sum
 :$\forall x, y \in \R: \paren {x + y}^2 = x^2 + 2 x y + y^2$
`proof`
Follows from the distribution of multiplication over addition:

{{begin-eqn}}
{{eqn | l = \left({x + y}\right)^2
      | r = \left({x + y}\right) \cdot \left({x + y}\right)
}}
{{eqn | r = x \cdot \left({x + y}\right) + y \cdot \left({x + y}\right)
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x \cdot x + x \cdot y + y \cdot x + y \cdot y
      | c = Real Multiplication Distributes over Addition
}}
{{eqn | r = x^2 + 2xy + y^2
      | c =
}}
{{end-eqn}}
{{qed}}
-/
theorem square_of_sum (x y : ℝ) : (x + y)^2 = (x^2 + 2*x*y + y^2) :=
begin
  calc (x + y)^2 = (x+y)*(x+y) : by auto [sq]
  ... = x*(x+y) + y*(x+y) : by auto [add_mul]
  ... = x*x + x*y + y*x + y*y : by auto [mul_comm, add_mul] using [ring]
  ... = x^2 + 2*x*y + y^2 : by auto [sq, mul_comm] using [ring]
end

/--`theorem`
Identity of Group is Unique
Let $\struct {G, \circ}$ be a group. Then there is a unique identity element $e \in G$.
`proof`
From Group has Latin Square Property, there exists a unique $x \in G$ such that:
:$a x = b$

and there exists a unique $y \in G$ such that:
:$y a = b$

Setting $b = a$, this becomes:

There exists a unique $x \in G$ such that:
:$a x = a$

and there exists a unique $y \in G$ such that:
:$y a = a$

These $x$ and $y$ are both $e$, by definition of identity element.
{{qed}}
-/
theorem group_identity_unique {G : Type*} [group G] : ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a :=
begin
  have h1 : ∀ a b : G, ∃! x : G, a * x = b, from by auto using [use (a⁻¹ * b)],
  have h2 : ∀ a b : G, ∃! y : G, y * a = b, from by auto using [use b * a⁻¹],

  have h3 : ∀ a : G, ∃! x : G, a * x = a, from by auto [h1],
  have h4 : ∀ a : G, ∃! y : G, y * a = a, from by auto [h2],

  have h5 : ∀ a : G, classical.some (h3 a).exists = (1 : G), from by auto [exists_unique.unique, h3, classical.some_spec, exists_unique.exists, mul_one],
  have h6 : ∀ a : G, classical.some (h4 a).exists = (1 : G), from by auto [exists_unique.unique, h4, classical.some_spec, exists_unique.exists, one_mul],

  show ∃! e : G, ∀ a : G, e * a = a ∧ a * e = a, from by auto [h3, h4, exists_unique.unique, classical.some_spec, exists_unique.exists] using [use (1 : G)],
end

/--`theorem`
Nesbitt's inequality
Let $a$, $b$ and $c$ be positive real numbers.

Then:
:$\dfrac a {b + c} + \dfrac b {a + c} + \dfrac c {a + b} \ge \dfrac 3 2$

`proof`
{{begin-eqn}}
{{eqn | l = \frac a {b + c} + \frac b {a + c} + \frac c {a + b}
      | o = \ge
      | r = \dfrac 3 2
}}
{{eqn | ll= \leadstoandfrom
      | l = \frac {a + b + c} {b + c} + \frac {a + b + c} {a + c} + \frac {a + b + c} {a + b}
      | o = \ge
      | r = \frac 9 2
      | c = by adding $3$
}}
{{eqn | ll= \leadstoandfrom
      | l = \frac {a + b + c} {b + c} + \frac {a + b + c} {a + c} + \frac {a + b + c} {a + b}
      | o = \ge
      | r = \frac {9 \paren {a + b + c} } {\paren {b + c} + \paren {a + c} + \paren {a + b} }
      | c = as $\dfrac {a + b + c} {\paren {b + c} + \paren {a + c} + \paren {a + b} } = \dfrac 1 2$
}}
{{eqn | ll= \leadstoandfrom
      | l = \frac {\frac 1 {b + c} + \frac 1 {a + c} + \frac 1 {a + b} } 3
      | o = \ge
      | r = \frac 3 {\paren {b + c} + \paren {a + c} + \paren {a + b} }
      | c = dividing by $3 \paren {a + b + c}$
}}
{{end-eqn}}
These are the arithmetic mean and the harmonic mean of $\dfrac 1 {b + c}$, $\dfrac 1 {a + c}$ and $\dfrac 1 {a + b}$.

From Arithmetic Mean is Never Less than Harmonic Mean the last inequality is true.

Thus Nesbitt's Inequality holds.
{{qed}}

-/
theorem  nesbitt_inequality {a b c : ℝ} (ha : 0 < a) (hb : 0 < b) (hc : 0 < c) : (a / (b + c)) + (b / (a + c)) + (c / (a + b)) ≥ (3 / 2) :=
FEW SHOT PROMPTS TO CODEX(END)-/


import Lean

open Lean Lean.Expr Lean.Meta

variable {n m : Nat}

example : n = m :=
  by apply Eq.trans
     -- n = ?b
     -- ?b = m
     sorry
     sorry
     sorry

#check @Eq.trans Nat n m

example {α} (a : α) (f : α → α) (h : ∀ a, f a = a) : f (f a) = a := by
  apply Eq.trans
  apply h
  apply h

#check mkFreshExprMVar

#check getLCtx

#check instantiateMVars

def someNumber : Nat := (. + 2) $ 3

#eval someNumber

#eval mkConst ``someNumber

#eval reduce (mkConst ``someNumber)

#reduce someNumber

def myAssumption (mvarId : MVarId) : MetaM Bool := do
  checkNotAssigned mvarId `myAssumption
  withMVarContext mvarId do
    let target ← getMVarType mvarId
    for ldecl in ← getLCtx do
      if ldecl.isAuxDecl then
        continue
      if ← isDefEq ldecl.type target then
        assignExprMVar mvarId ldecl.toExpr
        return true
    return false

syntax "custom_tactic" : tactic

macro_rules
| `(tactic| custom_tactic) => `(tactic| apply And.intro <;> custom_tactic)

macro_rules
| `(tactic| custom_tactic) => `(tactic| rfl)

example : 43 = 43 ∧ 42 = 42 := by
  custom_tactic

elab "custom_assump_2" : tactic =>
  Lean.Elab.Tactic.withMainContext do
    let goal ← Lean.Elab.Tactic.getMainGoal
    let goalType ← Lean.Elab.Tactic.getMainTarget
    let ctx ← Lean.MonadLCtx.getLCtx
    let option_matching_expr ← ctx.findDeclM? fun decl: Lean.LocalDecl => do
      let declExpr := decl.toExpr
      let declType ← Lean.Meta.inferType declExpr
      if ← Lean.Meta.isExprDefEq declType goalType
        then return Option.some declExpr
        else return Option.none
    match option_matching_expr with
    | some e => Lean.Elab.Tactic.closeMainGoal e
    | none => Lean.Meta.throwTacticEx `custom_assump_2 goal
                (m!"unable to find matching hypothesis of type ({goalType})")

example (H1 : 1 = 1) (H2 : 2 = 2)  : 2 = 2 := by
  custom_assump_2

example (H1 : 1 = 1)  : 2 = 2 := by
  custom_assump_2