l3lab/ntp-mathlib huggingface dataset:
/-- Core operation for binary heaps, expressed directly on arrays.
Given an array which is a max-heap, push item `i` up to restore the max-heap property. -/
def heapifyUp (lt : α → α → Bool) (a : Array α) (i : Fin a.size) :
    {a' : Array α // a'.size = a.size} :=
if i0 : i.1 = 0 then ⟨a, rfl⟩ else
  have : (i.1 - 1) / 2 < i := Nat.lt_of_le_of_lt (Nat.div_le_self ..) $
    Nat.sub_lt (Nat.pos_of_ne_zero i0) Nat.zero_lt_one
  let j := ⟨(i.1 - 1) / 2, Nat.lt_trans this i.2⟩
  if lt (a.get j) (a.get i) then
    let a' := a.swap i j
    let ⟨a₂, h₂⟩ := heapifyUp lt a' ⟨j.1, by rw [a.size_swap i j]; 

Proof state:
α : Type ?u.5387
lt : α → α → Bool
a : Array α
i : Fin (Array.size a)
i0 : ¬i.val = 0
this : (i.val - 1) / 2 < i.val
j : Fin (Array.size a) := { val := (i.val - 1) / 2, isLt := (_ : (i.val - 1) / 2 < Array.size a) }
a' : Array α := Array.swap a i j
⊢ j.val < Array.size a

Next tactic:
exact j.2
/-- Core operation for binary heaps, expressed directly on arrays.
Given an array which is a max-heap, push item `i` up to restore the max-heap property. -/
def heapifyUp (lt : α → α → Bool) (a : Array α) (i : Fin a.size) :
    {a' : Array α // a'.size = a.size} :=
if i0 : i.1 = 0 then ⟨a, rfl⟩ else
  have : (i.1 - 1) / 2 < i := Nat.lt_of_le_of_lt (Nat.div_le_self ..) $
    Nat.sub_lt (Nat.pos_of_ne_zero i0) Nat.zero_lt_one
  let j := ⟨(i.1 - 1) / 2, Nat.lt_trans this i.2⟩
  if lt (a.get j) (a.get i) then
    let a' := a.swap i j
    let ⟨a₂, h₂⟩ := heapifyUp lt a' ⟨j.1, by rw [a.size_swap i j]; exact j.2⟩
    ⟨a₂, h₂.trans (a.size_swap i j)⟩
  else ⟨a, rfl⟩
termination_by _ => i.1
decreasing_by 

Proof state:
α : Type u_1
lt : α → α → Bool
a : Array α
i : Fin (Array.size a)
i0 : ¬i.val = 0
this : (i.val - 1) / 2 < i.val
j : Fin (Array.size a) := { val := (i.val - 1) / 2, isLt := (_ : (i.val - 1) / 2 < Array.size a) }
h✝ : lt (Array.get a j) (Array.get a i) = true
a' : Array α := Array.swap a i j
⊢ (invImage (fun a => PSigma.casesOn a fun a snd => snd.val) instWellFoundedRelation).1
    { fst := a', snd := { val := j.val, isLt := (_ : j.val < Array.size a') } } { fst := a, snd := i }

Next tactic:
assumption
/-- `O(log n)`. Insert an element into a `BinaryHeap`, preserving the max-heap property. -/
def insert {lt} (self : BinaryHeap α lt) (x : α) : BinaryHeap α lt where
  arr := let n := self.size;
    heapifyUp lt (self.1.push x) ⟨n, by 

Proof state:
α : Type ?u.7413
lt : α → α → Bool
self : BinaryHeap α lt
x : α
n : Nat := size self
⊢ n < Array.size (Array.push self.arr x)

Next tactic:
rw [Array.size_push]
/-- `O(log n)`. Insert an element into a `BinaryHeap`, preserving the max-heap property. -/
def insert {lt} (self : BinaryHeap α lt) (x : α) : BinaryHeap α lt where
  arr := let n := self.size;
    heapifyUp lt (self.1.push x) ⟨n, by rw [Array.size_push]; 

Proof state:
α : Type ?u.7413
lt : α → α → Bool
self : BinaryHeap α lt
x : α
n : Nat := size self
⊢ n < Array.size self.arr + 1

Next tactic:
apply Nat.lt_succ_self
@[simp] theorem size_insert {lt} (self : BinaryHeap α lt) (x : α) :
  (self.insert x).size = self.size + 1 := by
  

Proof state:
α : Type u_1
lt : α → α → Bool
self : BinaryHeap α lt
x : α
⊢ size (insert self x) = size self + 1

Next tactic:
simp [insert, size, size_heapifyUp]
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
e : Array.size self.arr = 0
⊢ size self = size self - 1

Next tactic:
simp [size, e]
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by simp [size, e]⟩
  | n+1 =>
    have h0 := by 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
n : Nat
e : Array.size self.arr = Nat.succ n
⊢ 0 < Array.size self.arr

Next tactic:
rw [e]
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by simp [size, e]⟩
  | n+1 =>
    have h0 := by rw [e]; 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
n : Nat
e : Array.size self.arr = Nat.succ n
⊢ 0 < Nat.succ n

Next tactic:
apply Nat.succ_pos
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by simp [size, e]⟩
  | n+1 =>
    have h0 := by rw [e]; apply Nat.succ_pos
    have hn := by 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
n : Nat
e : Array.size self.arr = Nat.succ n
h0 : 0 < Array.size self.arr
⊢ n < Array.size self.arr

Next tactic:
rw [e]
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by simp [size, e]⟩
  | n+1 =>
    have h0 := by rw [e]; apply Nat.succ_pos
    have hn := by rw [e]; 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
n : Nat
e : Array.size self.arr = Nat.succ n
h0 : 0 < Array.size self.arr
⊢ n < Nat.succ n

Next tactic:
apply Nat.lt_succ_self
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by simp [size, e]⟩
  | n+1 =>
    have h0 := by rw [e]; apply Nat.succ_pos
    have hn := by rw [e]; apply Nat.lt_succ_self
    if hn0 : 0 < n then
      let a := self.1.swap ⟨0, h0⟩ ⟨n, hn⟩ |>.pop
      ⟨⟨heapifyDown lt a ⟨0, by 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
n : Nat
e : Array.size self.arr = Nat.succ n
h0 : 0 < Array.size self.arr
hn : n < Array.size self.arr
hn0 : 0 < n
a : Array α := Array.pop (Array.swap self.arr { val := 0, isLt := h0 } { val := n, isLt := hn })
⊢ 0 < Array.size a

Next tactic:
rwa [Array.size_pop, Array.size_swap, e]
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by simp [size, e]⟩
  | n+1 =>
    have h0 := by rw [e]; apply Nat.succ_pos
    have hn := by rw [e]; apply Nat.lt_succ_self
    if hn0 : 0 < n then
      let a := self.1.swap ⟨0, h0⟩ ⟨n, hn⟩ |>.pop
      ⟨⟨heapifyDown lt a ⟨0, by rwa [Array.size_pop, Array.size_swap, e]⟩⟩,
        by 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
n : Nat
e : Array.size self.arr = Nat.succ n
h0 : 0 < Array.size self.arr
hn : n < Array.size self.arr
hn0 : 0 < n
a : Array α := Array.pop (Array.swap self.arr { val := 0, isLt := h0 } { val := n, isLt := hn })
⊢ size { arr := (heapifyDown lt a { val := 0, isLt := (_ : 0 < Array.size a) }).val } = size self - 1

Next tactic:
simp [size]
/-- Auxiliary for `popMax`. -/
def popMaxAux {lt} (self : BinaryHeap α lt) : {a' : BinaryHeap α lt // a'.size = self.size - 1} :=
  match e: self.1.size with
  | 0 => ⟨self, by simp [size, e]⟩
  | n+1 =>
    have h0 := by rw [e]; apply Nat.succ_pos
    have hn := by rw [e]; apply Nat.lt_succ_self
    if hn0 : 0 < n then
      let a := self.1.swap ⟨0, h0⟩ ⟨n, hn⟩ |>.pop
      ⟨⟨heapifyDown lt a ⟨0, by rwa [Array.size_pop, Array.size_swap, e]⟩⟩,
        by simp [size]⟩
    else
      ⟨⟨self.1.pop⟩, by 

Proof state:
α : Type ?u.8157
lt : α → α → Bool
self : BinaryHeap α lt
n : Nat
e : Array.size self.arr = Nat.succ n
h0 : 0 < Array.size self.arr
hn : n < Array.size self.arr
hn0 : ¬0 < n
⊢ size { arr := Array.pop self.arr } = size self - 1

Next tactic:
simp [size]
theorem size_pos_of_max {lt} {self : BinaryHeap α lt} (e : self.max = some x) : 0 < self.size :=
  Decidable.of_not_not fun h: ¬ 0 < self.1.size ↦ by 

Proof state:
α : Type u_1
x : α
lt : α → α → Bool
self : BinaryHeap α lt
e : max self = some x
h : ¬0 < Array.size self.arr
⊢ False

Next tactic:
simp [BinaryHeap.max, Array.get?, h] at e
/-- `O(log n)`. Equivalent to `extractMax (self.insert x)`, except that extraction cannot fail. -/
def insertExtractMax {lt} (self : BinaryHeap α lt) (x : α) : α × BinaryHeap α lt :=
  match e: self.max with
  | none => (x, self)
  | some m =>
    if lt x m then
      let a := self.1.set ⟨0, size_pos_of_max e⟩ x
      (m, ⟨heapifyDown lt a ⟨0, by 

Proof state:
α : Type ?u.10388
lt : α → α → Bool
self : BinaryHeap α lt
x m : α
e : max self = some m
a : Array α := Array.set self.arr { val := 0, isLt := (_ : 0 < size self) } x
⊢ 0 < Array.size a

Next tactic:
simp
/-- `O(log n)`. Equivalent to `extractMax (self.insert x)`, except that extraction cannot fail. -/
def insertExtractMax {lt} (self : BinaryHeap α lt) (x : α) : α × BinaryHeap α lt :=
  match e: self.max with
  | none => (x, self)
  | some m =>
    if lt x m then
      let a := self.1.set ⟨0, size_pos_of_max e⟩ x
      (m, ⟨heapifyDown lt a ⟨0, by simp; 

Proof state:
α : Type ?u.10388
lt : α → α → Bool
self : BinaryHeap α lt
x m : α
e : max self = some m
a : Array α := Array.set self.arr { val := 0, isLt := (_ : 0 < size self) } x
⊢ 0 < Array.size self.arr

Next tactic:
exact size_pos_of_max e
/-- `O(log n)`. Equivalent to `(self.max, self.popMax.insert x)`. -/
def replaceMax {lt} (self : BinaryHeap α lt) (x : α) : Option α × BinaryHeap α lt :=
  match e: self.max with
  | none => (none, ⟨self.1.push x⟩)
  | some m =>
    let a := self.1.set ⟨0, size_pos_of_max e⟩ x
    (some m, ⟨heapifyDown lt a ⟨0, by 

Proof state:
α : Type ?u.11378
lt : α → α → Bool
self : BinaryHeap α lt
x m : α
e : max self = some m
a : Array α := Array.set self.arr { val := 0, isLt := (_ : 0 < size self) } x
⊢ 0 < Array.size a

Next tactic:
simp
/-- `O(log n)`. Equivalent to `(self.max, self.popMax.insert x)`. -/
def replaceMax {lt} (self : BinaryHeap α lt) (x : α) : Option α × BinaryHeap α lt :=
  match e: self.max with
  | none => (none, ⟨self.1.push x⟩)
  | some m =>
    let a := self.1.set ⟨0, size_pos_of_max e⟩ x
    (some m, ⟨heapifyDown lt a ⟨0, by simp; 

Proof state:
α : Type ?u.11378
lt : α → α → Bool
self : BinaryHeap α lt
x m : α
e : max self = some m
a : Array α := Array.set self.arr { val := 0, isLt := (_ : 0 < size self) } x
⊢ 0 < Array.size self.arr

Next tactic:
exact size_pos_of_max e
/-- `O(log n)`. Replace the value at index `i` by `x`. Assumes that `x ≤ self.get i`. -/
def decreaseKey {lt} (self : BinaryHeap α lt) (i : Fin self.size) (x : α) : BinaryHeap α lt where
  arr := heapifyDown lt (self.1.set i x) ⟨i, by 

Proof state:
α : Type ?u.12194
lt : α → α → Bool
self : BinaryHeap α lt
i : Fin (size self)
x : α
⊢ i.val < Array.size (Array.set self.arr i x)

Next tactic:
rw [self.1.size_set]
/-- `O(log n)`. Replace the value at index `i` by `x`. Assumes that `x ≤ self.get i`. -/
def decreaseKey {lt} (self : BinaryHeap α lt) (i : Fin self.size) (x : α) : BinaryHeap α lt where
  arr := heapifyDown lt (self.1.set i x) ⟨i, by rw [self.1.size_set]; 

Proof state:
α : Type ?u.12194
lt : α → α → Bool
self : BinaryHeap α lt
i : Fin (size self)
x : α
⊢ i.val < Array.size self.arr

Next tactic:
exact i.2
/-- `O(log n)`. Replace the value at index `i` by `x`. Assumes that `self.get i ≤ x`. -/
def increaseKey {lt} (self : BinaryHeap α lt) (i : Fin self.size) (x : α) : BinaryHeap α lt where
  arr := heapifyUp lt (self.1.set i x) ⟨i, by 

Proof state:
α : Type ?u.12759
lt : α → α → Bool
self : BinaryHeap α lt
i : Fin (size self)
x : α
⊢ i.val < Array.size (Array.set self.arr i x)

Next tactic:
rw [self.1.size_set]
/-- `O(log n)`. Replace the value at index `i` by `x`. Assumes that `self.get i ≤ x`. -/
def increaseKey {lt} (self : BinaryHeap α lt) (i : Fin self.size) (x : α) : BinaryHeap α lt where
  arr := heapifyUp lt (self.1.set i x) ⟨i, by rw [self.1.size_set]; 

Proof state:
α : Type ?u.12759
lt : α → α → Bool
self : BinaryHeap α lt
i : Fin (size self)
x : α
⊢ i.val < Array.size self.arr

Next tactic:
exact i.2
/-- `O(n log n)`. Sort an array using a `BinaryHeap`. -/
@[specialize] def Array.heapSort (a : Array α) (lt : α → α → Bool) : Array α :=
  let gt y x := lt x y
  let rec loop (a : BinaryHeap α gt) (out : Array α) : Array α :=
    match e: a.max with
    | none => out
    | some x =>
      have : a.popMax.size < a.size := by
        

Proof state:
α : Type ?u.13558
a✝ : Array α
lt : α → α → Bool
gt : α → α → Bool := fun y x => lt x y
a : BinaryHeap α gt
out : Array α
x : α
e : BinaryHeap.max a = some x
⊢ BinaryHeap.size (BinaryHeap.popMax a) < BinaryHeap.size a

Next tactic:
simp
/-- `O(n log n)`. Sort an array using a `BinaryHeap`. -/
@[specialize] def Array.heapSort (a : Array α) (lt : α → α → Bool) : Array α :=
  let gt y x := lt x y
  let rec loop (a : BinaryHeap α gt) (out : Array α) : Array α :=
    match e: a.max with
    | none => out
    | some x =>
      have : a.popMax.size < a.size := by
        simp; 

Proof state:
α : Type ?u.13558
a✝ : Array α
lt : α → α → Bool
gt : α → α → Bool := fun y x => lt x y
a : BinaryHeap α gt
out : Array α
x : α
e : BinaryHeap.max a = some x
⊢ BinaryHeap.size a - 1 < BinaryHeap.size a

Next tactic:
exact Nat.sub_lt (BinaryHeap.size_pos_of_max e) Nat.zero_lt_one
/-- `O(n log n)`. Sort an array using a `BinaryHeap`. -/
@[specialize] def Array.heapSort (a : Array α) (lt : α → α → Bool) : Array α :=
  let gt y x := lt x y
  let rec loop (a : BinaryHeap α gt) (out : Array α) : Array α :=
    match e: a.max with
    | none => out
    | some x =>
      have : a.popMax.size < a.size := by
        simp; exact Nat.sub_lt (BinaryHeap.size_pos_of_max e) Nat.zero_lt_one
      loop a.popMax (out.push x)
  loop (a.toBinaryHeap gt) #[]
termination_by _ => a.size
decreasing_by 

Proof state:
α : Type u_1
lt : α → α → Bool
a : BinaryHeap α fun y x => lt x y
out : Array α
gt : α → α → Bool := fun y x => lt x y
x : α
e : BinaryHeap.max a = some x
this : BinaryHeap.size (BinaryHeap.popMax a) < BinaryHeap.size a
⊢ (invImage (fun a => PSigma.casesOn a fun a snd => BinaryHeap.size a) instWellFoundedRelation).1
    { fst := BinaryHeap.popMax a, snd := push out x } { fst := a, snd := out }

Next tactic:
assumption
/-- Assume that `f` is differentiable inside a convex set `s`, and that its derivative `f'` is
differentiable at a point `x`. Then, given two vectors `v` and `w` pointing inside `s`, one can
Taylor-expand to order two the function `f` on the segment `[x + h v, x + h (v + w)]`, giving a
bilinear estimate for `f (x + hv + hw) - f (x + hv)` in terms of `f' w` and of `f'' ⬝ w`, up to
`o(h^2)`.

This is a technical statement used to show that the second derivative is symmetric. -/
theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
    (hw : x + v + w ∈ interior s) :
    (fun h : ℝ => f (x + h • v + h • w)
        - f (x + h • v) - h • f' x w - h ^ 2 • f'' v w - (h ^ 2 / 2) • f'' w w) =o[𝓝[>] 0]
      fun h => h ^ 2 := by
  -- it suffices to check that the expression is bounded by `ε * ((‖v‖ + ‖w‖) * ‖w‖) * h^2` for
  -- small enough `h`, for any positive `ε`.
  

Proof state:
E : Type u_1
F : Type u_2
inst✝³ : NormedAddCommGroup E
inst✝² : NormedSpace ℝ E
inst✝¹ : NormedAddCommGroup F
inst✝ : NormedSpace ℝ F
s : Set E
s_conv : Convex ℝ s
f : E → F
f' : E → E →L[ℝ] F
f'' : E →L[ℝ] E →L[ℝ] F
hf : ∀ x ∈ interior s, HasFDerivAt f (f' x) x
x : E
xs : x ∈ s
hx : HasFDerivWithinAt f' f'' (interior s) x
v w : E
hv : x + v ∈ interior s
hw : x + v + w ∈ interior s
⊢ (fun h =>
      f (x + h • v + h • w) - f (x + h • v) - h • (f' x) w - h ^ 2 • (f'' v) w - (h ^ 2 / 2) • (f'' w) w) =o[𝓝[>] 0]
    fun h => h ^ 2

Next tactic:
refine' IsLittleO.trans_isBigO
    (isLittleO_iff.2 fun ε εpos => _) (isBigO_const_mul_self ((‖v‖ + ‖w‖) * ‖w‖) _ _)
/-- Assume that `f` is differentiable inside a convex set `s`, and that its derivative `f'` is
differentiable at a point `x`. Then, given two vectors `v` and `w` pointing inside `s`, one can
Taylor-expand to order two the function `f` on the segment `[x + h v, x + h (v + w)]`, giving a
bilinear estimate for `f (x + hv + hw) - f (x + hv)` in terms of `f' w` and of `f'' ⬝ w`, up to
`o(h^2)`.

This is a technical statement used to show that the second derivative is symmetric. -/
theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
    (hw : x + v + w ∈ interior s) :
    (fun h : ℝ => f (x + h • v + h • w)
        - f (x + h • v) - h • f' x w - h ^ 2 • f'' v w - (h ^ 2 / 2) • f'' w w) =o[𝓝[>] 0]
      fun h => h ^ 2 := by
  -- it suffices to check that the expression is bounded by `ε * ((‖v‖ + ‖w‖) * ‖w‖) * h^2` for
  -- small enough `h`, for any positive `ε`.
  refine' IsLittleO.trans_isBigO
    (isLittleO_iff.2 fun ε εpos => _) (isBigO_const_mul_self ((‖v‖ + ‖w‖) * ‖w‖) _ _)
  -- consider a ball of radius `δ` around `x` in which the Taylor approximation for `f''` is
  -- good up to `δ`.
  

Proof state:
E : Type u_1
F : Type u_2
inst✝³ : NormedAddCommGroup E
inst✝² : NormedSpace ℝ E
inst✝¹ : NormedAddCommGroup F
inst✝ : NormedSpace ℝ F
s : Set E
s_conv : Convex ℝ s
f : E → F
f' : E → E →L[ℝ] F
f'' : E →L[ℝ] E →L[ℝ] F
hf : ∀ x ∈ interior s, HasFDerivAt f (f' x) x
x : E
xs : x ∈ s
hx : HasFDerivWithinAt f' f'' (interior s) x
v w : E
hv : x + v ∈ interior s
hw : x + v + w ∈ interior s
ε : ℝ
εpos : 0 < ε
⊢ ∀ᶠ (x_1 : ℝ) in 𝓝[>] 0,
    ‖f (x + x_1 • v + x_1 • w) - f (x + x_1 • v) - x_1 • (f' x) w - x_1 ^ 2 • (f'' v) w - (x_1 ^ 2 / 2) • (f'' w) w‖ ≤
      ε * ‖(‖v‖ + ‖w‖) * ‖w‖ * x_1 ^ 2‖

Next tactic:
rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, isLittleO_iff] at hx
/-- Assume that `f` is differentiable inside a convex set `s`, and that its derivative `f'` is
differentiable at a point `x`. Then, given two vectors `v` and `w` pointing inside `s`, one can
Taylor-expand to order two the function `f` on the segment `[x + h v, x + h (v + w)]`, giving a
bilinear estimate for `f (x + hv + hw) - f (x + hv)` in terms of `f' w` and of `f'' ⬝ w`, up to
`o(h^2)`.

This is a technical statement used to show that the second derivative is symmetric. -/
theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
    (hw : x + v + w ∈ interior s) :
    (fun h : ℝ => f (x + h • v + h • w)
        - f (x + h • v) - h • f' x w - h ^ 2 • f'' v w - (h ^ 2 / 2) • f'' w w) =o[𝓝[>] 0]
      fun h => h ^ 2 := by
  -- it suffices to check that the expression is bounded by `ε * ((‖v‖ + ‖w‖) * ‖w‖) * h^2` for
  -- small enough `h`, for any positive `ε`.
  refine' IsLittleO.trans_isBigO
    (isLittleO_iff.2 fun ε εpos => _) (isBigO_const_mul_self ((‖v‖ + ‖w‖) * ‖w‖) _ _)
  -- consider a ball of radius `δ` around `x` in which the Taylor approximation for `f''` is
  -- good up to `δ`.
  rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, isLittleO_iff] at hx
  

Proof state:
E : Type u_1
F : Type u_2
inst✝³ : NormedAddCommGroup E
inst✝² : NormedSpace ℝ E
inst✝¹ : NormedAddCommGroup F
inst✝ : NormedSpace ℝ F
s : Set E
s_conv : Convex ℝ s
f : E → F
f' : E → E →L[ℝ] F
f'' : E →L[ℝ] E →L[ℝ] F
hf : ∀ x ∈ interior s, HasFDerivAt f (f' x) x
x : E
xs : x ∈ s
hx : ∀ ⦃c : ℝ⦄, 0 < c → ∀ᶠ (x_1 : E) in 𝓝[interior s] x, ‖f' x_1 - f' x - f'' (x_1 - x)‖ ≤ c * ‖x_1 - x‖
v w : E
hv : x + v ∈ interior s
hw : x + v + w ∈ interior s
ε : ℝ
εpos : 0 < ε
⊢ ∀ᶠ (x_1 : ℝ) in 𝓝[>] 0,
    ‖f (x + x_1 • v + x_1 • w) - f (x + x_1 • v) - x_1 • (f' x) w - x_1 ^ 2 • (f'' v) w - (x_1 ^ 2 / 2) • (f'' w) w‖ ≤
      ε * ‖(‖v‖ + ‖w‖) * ‖w‖ * x_1 ^ 2‖

Next tactic:
rcases Metric.mem_nhdsWithin_iff.1 (hx εpos) with ⟨δ, δpos, sδ⟩
/-- Assume that `f` is differentiable inside a convex set `s`, and that its derivative `f'` is
differentiable at a point `x`. Then, given two vectors `v` and `w` pointing inside `s`, one can
Taylor-expand to order two the function `f` on the segment `[x + h v, x + h (v + w)]`, giving a
bilinear estimate for `f (x + hv + hw) - f (x + hv)` in terms of `f' w` and of `f'' ⬝ w`, up to
`o(h^2)`.

This is a technical statement used to show that the second derivative is symmetric. -/
theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
    (hw : x + v + w ∈ interior s) :
    (fun h : ℝ => f (x + h • v + h • w)
        - f (x + h • v) - h • f' x w - h ^ 2 • f'' v w - (h ^ 2 / 2) • f'' w w) =o[𝓝[>] 0]
      fun h => h ^ 2 := by
  -- it suffices to check that the expression is bounded by `ε * ((‖v‖ + ‖w‖) * ‖w‖) * h^2` for
  -- small enough `h`, for any positive `ε`.
  refine' IsLittleO.trans_isBigO
    (isLittleO_iff.2 fun ε εpos => _) (isBigO_const_mul_self ((‖v‖ + ‖w‖) * ‖w‖) _ _)
  -- consider a ball of radius `δ` around `x` in which the Taylor approximation for `f''` is
  -- good up to `δ`.
  rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, isLittleO_iff] at hx
  rcases Metric.mem_nhdsWithin_iff.1 (hx εpos) with ⟨δ, δpos, sδ⟩
  

Proof state:
case intro.intro
E : Type u_1
F : Type u_2
inst✝³ : NormedAddCommGroup E
inst✝² : NormedSpace ℝ E
inst✝¹ : NormedAddCommGroup F
inst✝ : NormedSpace ℝ F
s : Set E
s_conv : Convex ℝ s
f : E → F
f' : E → E →L[ℝ] F
f'' : E →L[ℝ] E →L[ℝ] F
hf : ∀ x ∈ interior s, HasFDerivAt f (f' x) x
x : E
xs : x ∈ s
hx : ∀ ⦃c : ℝ⦄, 0 < c → ∀ᶠ (x_1 : E) in 𝓝[interior s] x, ‖f' x_1 - f' x - f'' (x_1 - x)‖ ≤ c * ‖x_1 - x‖
v w : E
hv : x + v ∈ interior s
hw : x + v + w ∈ interior s
ε : ℝ
εpos : 0 < ε
δ : ℝ
δpos : δ > 0
sδ : Metric.ball x δ ∩ interior s ⊆ {x_1 | (fun x_2 => ‖f' x_2 - f' x - f'' (x_2 - x)‖ ≤ ε * ‖x_2 - x‖) x_1}
⊢ ∀ᶠ (x_1 : ℝ) in 𝓝[>] 0,
    ‖f (x + x_1 • v + x_1 • w) - f (x + x_1 • v) - x_1 • (f' x) w - x_1 ^ 2 • (f'' v) w - (x_1 ^ 2 / 2) • (f'' w) w‖ ≤
      ε * ‖(‖v‖ + ‖w‖) * ‖w‖ * x_1 ^ 2‖

Next tactic:
have E1 : ∀ᶠ h in 𝓝[>] (0 : ℝ), h * (‖v‖ + ‖w‖) < δ := by
    have : Filter.Tendsto (fun h => h * (‖v‖ + ‖w‖)) (𝓝[>] (0 : ℝ)) (𝓝 (0 * (‖v‖ + ‖w‖))) :=
      (continuous_id.mul continuous_const).continuousWithinAt
    apply (tendsto_order.1 this).2 δ
    simpa only [zero_mul] using δpos
/-- Assume that `f` is differentiable inside a convex set `s`, and that its derivative `f'` is
differentiable at a point `x`. Then, given two vectors `v` and `w` pointing inside `s`, one can
Taylor-expand to order two the function `f` on the segment `[x + h v, x + h (v + w)]`, giving a
bilinear estimate for `f (x + hv + hw) - f (x + hv)` in terms of `f' w` and of `f'' ⬝ w`, up to
`o(h^2)`.

This is a technical statement used to show that the second derivative is symmetric. -/
theorem Convex.taylor_approx_two_segment {v w : E} (hv : x + v ∈ interior s)
    (hw : x + v + w ∈ interior s) :
    (fun h : ℝ => f (x + h • v + h • w)
        - f (x + h • v) - h • f' x w - h ^ 2 • f'' v w - (h ^ 2 / 2) • f'' w w) =o[𝓝[>] 0]
      fun h => h ^ 2 := by
  -- it suffices to check that the expression is bounded by `ε * ((‖v‖ + ‖w‖) * ‖w‖) * h^2` for
  -- small enough `h`, for any positive `ε`.
  refine' IsLittleO.trans_isBigO
    (isLittleO_iff.2 fun ε εpos => _) (isBigO_const_mul_self ((‖v‖ + ‖w‖) * ‖w‖) _ _)
  -- consider a ball of radius `δ` around `x` in which the Taylor approximation for `f''` is
  -- good up to `δ`.
  rw [HasFDerivWithinAt, hasFDerivAtFilter_iff_isLittleO, isLittleO_iff] at hx
  rcases Metric.mem_nhdsWithin_iff.1 (hx εpos) with ⟨δ, δpos, sδ⟩
  have E1 : ∀ᶠ h in 𝓝[>] (0 : ℝ), h * (‖v‖ + ‖w‖) < δ := by
    

Proof state:
E : Type u_1
F : Type u_2
inst✝³ : NormedAddCommGroup E
inst✝² : NormedSpace ℝ E
inst✝¹ : NormedAddCommGroup F
inst✝ : NormedSpace ℝ F
s : Set E
s_conv : Convex ℝ s
f : E → F
f' : E → E →L[ℝ] F
f'' : E →L[ℝ] E →L[ℝ] F
hf : ∀ x ∈ interior s, HasFDerivAt f (f' x) x
x : E
xs : x ∈ s
hx : ∀ ⦃c : ℝ⦄, 0 < c → ∀ᶠ (x_1 : E) in 𝓝[interior s] x, ‖f' x_1 - f' x - f'' (x_1 - x)‖ ≤ c * ‖x_1 - x‖
v w : E
hv : x + v ∈ interior s
hw : x + v + w ∈ interior s
ε : ℝ
εpos : 0 < ε
δ : ℝ
δpos : δ > 0
sδ : Metric.ball x δ ∩ interior s ⊆ {x_1 | (fun x_2 => ‖f' x_2 - f' x - f'' (x_2 - x)‖ ≤ ε * ‖x_2 - x‖) x_1}
⊢ ∀ᶠ (h : ℝ) in 𝓝[>] 0, h * (‖v‖ + ‖w‖) < δ

Next tactic:
have : Filter.Tendsto (fun h => h * (‖v‖ + ‖w‖)) (𝓝[>] (0 : ℝ)) (𝓝 (0 * (‖v‖ + ‖w‖))) :=
      (continuous_id.mul continuous_const).continuousWithinAt