import Mathlib.Analysis.Calculus.FDeriv.Basic import Mathlib.Analysis.Calculus.FDeriv.Symmetric import Mathlib.Analysis.Calculus.ContDiff.Basic import Mathlib.Topology.Basic import Mathlib.Topology.Defs.Filter variable {π•œ : Type*} [NontriviallyNormedField π•œ] variable {E : Type*} [NormedAddCommGroup E] [NormedSpace π•œ E] variable {F : Type*} [NormedAddCommGroup F] [NormedSpace π•œ F] variable {G : Type*} [NormedAddCommGroup G] [NormedSpace π•œ G] variable (π•œ) noncomputable def partialDeriv : E β†’ (E β†’ F) β†’ (E β†’ F) := fun v ↦ (fun f ↦ (fun w ↦ fderiv π•œ f w v)) theorem partialDeriv_eventuallyEq' {f₁ fβ‚‚ : E β†’ F} {x : E} (h : f₁ =αΆ [nhds x] fβ‚‚) : βˆ€ v : E, partialDeriv π•œ v f₁ =αΆ [nhds x] partialDeriv π•œ v fβ‚‚ := by unfold partialDeriv intro v apply Filter.EventuallyEq.compβ‚‚ exact Filter.EventuallyEq.fderiv h simp theorem partialDeriv_smul₁ {f : E β†’ F} {a : π•œ} {v : E} : partialDeriv π•œ (a β€’ v) f = a β€’ partialDeriv π•œ v f := by unfold partialDeriv conv => left intro w rw [map_smul] theorem partialDeriv_add₁ {f : E β†’ F} {v₁ vβ‚‚ : E} : partialDeriv π•œ (v₁ + vβ‚‚) f = (partialDeriv π•œ v₁ f) + (partialDeriv π•œ vβ‚‚ f) := by unfold partialDeriv conv => left intro w rw [map_add] theorem partialDeriv_smulβ‚‚ {f : E β†’ F} {a : π•œ} {v : E} : partialDeriv π•œ v (a β€’ f) = a β€’ partialDeriv π•œ v f := by unfold partialDeriv funext w have : a β€’ f = fun y ↦ a β€’ f y := by rfl rw [this] by_cases ha : a = 0 Β· rw [ha] simp Β· by_cases hf : DifferentiableAt π•œ f w Β· rw [fderiv_const_smul hf] simp Β· have : Β¬DifferentiableAt π•œ (fun y => a β€’ f y) w := by by_contra contra let ZZ := DifferentiableAt.const_smul contra a⁻¹ have : (fun y => a⁻¹ β€’ a β€’ f y) = f := by funext i rw [← smul_assoc, smul_eq_mul, mul_comm, mul_inv_cancel ha] simp rw [this] at ZZ exact hf ZZ simp rw [fderiv_zero_of_not_differentiableAt hf] rw [fderiv_zero_of_not_differentiableAt this] simp theorem partialDeriv_addβ‚‚ {f₁ fβ‚‚ : E β†’ F} (h₁ : Differentiable π•œ f₁) (hβ‚‚ : Differentiable π•œ fβ‚‚) : βˆ€ v : E, partialDeriv π•œ v (f₁ + fβ‚‚) = (partialDeriv π•œ v f₁) + (partialDeriv π•œ v fβ‚‚) := by unfold partialDeriv intro v have : f₁ + fβ‚‚ = fun y ↦ f₁ y + fβ‚‚ y := by rfl rw [this] conv => left intro w left rw [fderiv_add (h₁ w) (hβ‚‚ w)] theorem partialDeriv_addβ‚‚_differentiableAt {f₁ fβ‚‚ : E β†’ F} {v : E} {x : E} (h₁ : DifferentiableAt π•œ f₁ x) (hβ‚‚ : DifferentiableAt π•œ fβ‚‚ x) : partialDeriv π•œ v (f₁ + fβ‚‚) x = (partialDeriv π•œ v f₁) x + (partialDeriv π•œ v fβ‚‚) x := by unfold partialDeriv have : f₁ + fβ‚‚ = fun y ↦ f₁ y + fβ‚‚ y := by rfl rw [this] rw [fderiv_add h₁ hβ‚‚] rfl theorem partialDeriv_addβ‚‚_contDiffAt {f₁ fβ‚‚ : E β†’ F} {v : E} {x : E} (h₁ : ContDiffAt π•œ 1 f₁ x) (hβ‚‚ : ContDiffAt π•œ 1 fβ‚‚ x) : partialDeriv π•œ v (f₁ + fβ‚‚) =αΆ [nhds x] (partialDeriv π•œ v f₁) + (partialDeriv π•œ v fβ‚‚) := by obtain ⟨f₁', u₁, hu₁, _, hf₁'⟩ := contDiffAt_one_iff.1 h₁ obtain ⟨fβ‚‚', uβ‚‚, huβ‚‚, _, hfβ‚‚'⟩ := contDiffAt_one_iff.1 hβ‚‚ apply Filter.eventuallyEq_iff_exists_mem.2 use u₁ ∩ uβ‚‚ constructor Β· exact Filter.inter_mem hu₁ huβ‚‚ Β· intro x hx simp apply partialDeriv_addβ‚‚_differentiableAt π•œ exact (hf₁' x (Set.mem_of_mem_inter_left hx)).differentiableAt exact (hfβ‚‚' x (Set.mem_of_mem_inter_right hx)).differentiableAt theorem partialDeriv_compContLin {f : E β†’ F} {l : F β†’L[π•œ] G} {v : E} (h : Differentiable π•œ f) : partialDeriv π•œ v (l ∘ f) = l ∘ partialDeriv π•œ v f := by unfold partialDeriv conv => left intro w left rw [fderiv.comp w (ContinuousLinearMap.differentiableAt l) (h w)] simp rfl theorem partialDeriv_compContLinAt {f : E β†’ F} {l : F β†’L[π•œ] G} {v : E} {x : E} (h : DifferentiableAt π•œ f x) : (partialDeriv π•œ v (l ∘ f)) x = (l ∘ partialDeriv π•œ v f) x:= by unfold partialDeriv rw [fderiv.comp x (ContinuousLinearMap.differentiableAt l) h] simp theorem partialDeriv_compCLE {f : E β†’ F} {l : F ≃L[π•œ] G} {v : E} : partialDeriv π•œ v (l ∘ f) = l ∘ partialDeriv π•œ v f := by funext x by_cases hyp : DifferentiableAt π•œ f x Β· let lCLM : F β†’L[π•œ] G := l suffices shyp : partialDeriv π•œ v (lCLM ∘ f) x = (lCLM ∘ partialDeriv π•œ v f) x from by tauto apply partialDeriv_compContLinAt exact hyp Β· unfold partialDeriv rw [fderiv_zero_of_not_differentiableAt] simp rw [fderiv_zero_of_not_differentiableAt] simp exact hyp rw [ContinuousLinearEquiv.comp_differentiableAt_iff] exact hyp theorem partialDeriv_contDiff {n : β„•} {f : E β†’ F} (h : ContDiff π•œ (n + 1) f) : βˆ€ v : E, ContDiff π•œ n (partialDeriv π•œ v f) := by unfold partialDeriv intro v let A := (contDiff_succ_iff_fderiv.1 h).right simp at A have : (fun w => (fderiv π•œ f w) v) = (fun f => f v) ∘ (fun w => (fderiv π•œ f w)) := by rfl rw [this] refine ContDiff.comp ?hg A refine ContDiff.of_succ ?hg.h refine ContDiff.clm_apply ?hg.h.hf ?hg.h.hg exact contDiff_id exact contDiff_const theorem partialDeriv_contDiffAt {n : β„•} {f : E β†’ F} {x : E} (h : ContDiffAt π•œ (n + 1) f x) : βˆ€ v : E, ContDiffAt π•œ n (partialDeriv π•œ v f) x := by unfold partialDeriv intro v let eval_at_v : (E β†’L[π•œ] F) β†’L[π•œ] F := { toFun := fun l ↦ l v map_add' := by simp map_smul' := by simp } have : (fun w => (fderiv π•œ f w) v) = eval_at_v ∘ (fun w => (fderiv π•œ f w)) := by rfl rw [this] apply ContDiffAt.continuousLinearMap_comp -- ContDiffAt π•œ (↑n) (fun w => fderiv π•œ f w) x apply ContDiffAt.fderiv_right h rfl lemma partialDeriv_fderiv {f : E β†’ F} (hf : ContDiff π•œ 2 f) (z a b : E) : fderiv π•œ (fderiv π•œ f) z b a = partialDeriv π•œ b (partialDeriv π•œ a f) z := by unfold partialDeriv rw [fderiv_clm_apply] Β· simp Β· exact (contDiff_succ_iff_fderiv.1 hf).2.differentiable le_rfl z Β· simp lemma partialDeriv_fderivOn {s : Set E} {f : E β†’ F} (hs : IsOpen s) (hf : ContDiffOn π•œ 2 f s) (a b : E) : βˆ€ z ∈ s, fderiv π•œ (fderiv π•œ f) z b a = partialDeriv π•œ b (partialDeriv π•œ a f) z := by intro z hz unfold partialDeriv rw [fderiv_clm_apply] Β· simp Β· convert DifferentiableOn.differentiableAt _ (IsOpen.mem_nhds hs hz) apply ContDiffOn.differentiableOn _ (Submonoid.oneLE.proof_2 β„•βˆž) exact ((contDiffOn_succ_iff_fderiv_of_isOpen hs).1 hf).2 Β· simp theorem partialDeriv_eventuallyEq {f₁ fβ‚‚ : E β†’ F} {x : E} (h : f₁ =αΆ [nhds x] fβ‚‚) : βˆ€ v : E, partialDeriv π•œ v f₁ x = partialDeriv π•œ v fβ‚‚ x := by unfold partialDeriv rw [Filter.EventuallyEq.fderiv_eq h] exact fun v => rfl section restrictScalars theorem partialDeriv_smul'β‚‚ (π•œ : Type*) [NontriviallyNormedField π•œ] {π•œ' : Type*} [NontriviallyNormedField π•œ'] [NormedAlgebra π•œ π•œ'] {E : Type*} [NormedAddCommGroup E] [NormedSpace π•œ E] {F : Type*} [NormedAddCommGroup F] [NormedSpace π•œ F] [NormedSpace π•œ' F] [IsScalarTower π•œ π•œ' F] {f : E β†’ F} {a : π•œ'} {v : E} : partialDeriv π•œ v (a β€’ f) = a β€’ partialDeriv π•œ v f := by funext w by_cases ha : a = 0 Β· unfold partialDeriv have : a β€’ f = fun y ↦ a β€’ f y := by rfl rw [this, ha] simp Β· -- Now a is not zero. We present scalar multiplication with a as a continuous linear equivalence. let smulCLM : F ≃L[π•œ] F := { toFun := fun x ↦ a β€’ x map_add' := fun x y => DistribSMul.smul_add a x y map_smul' := fun m x => (smul_comm ((RingHom.id π•œ) m) a x).symm invFun := fun x ↦ a⁻¹ β€’ x left_inv := by intro x simp rw [← smul_assoc, smul_eq_mul, mul_comm, mul_inv_cancel ha, one_smul] right_inv := by intro x simp rw [← smul_assoc, smul_eq_mul, mul_inv_cancel ha, one_smul] continuous_toFun := continuous_const_smul a continuous_invFun := continuous_const_smul a⁻¹ } have : a β€’ f = smulCLM ∘ f := by tauto rw [this] rw [partialDeriv_compCLE] tauto theorem partialDeriv_restrictScalars (π•œ : Type*) [NontriviallyNormedField π•œ] {π•œ' : Type*} [NontriviallyNormedField π•œ'] [NormedAlgebra π•œ π•œ'] {E : Type*} [NormedAddCommGroup E] [NormedSpace π•œ E] [NormedSpace π•œ' E] [IsScalarTower π•œ π•œ' E] {F : Type*} [NormedAddCommGroup F] [NormedSpace π•œ F] [NormedSpace π•œ' F] [IsScalarTower π•œ π•œ' F] {f : E β†’ F} {v : E} : Differentiable π•œ' f β†’ partialDeriv π•œ v f = partialDeriv π•œ' v f := by intro hf unfold partialDeriv funext x rw [(hf x).fderiv_restrictScalars π•œ] simp theorem partialDeriv_comm {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] {f : E β†’ F} (h : ContDiff ℝ 2 f) : βˆ€ v₁ vβ‚‚ : E, partialDeriv ℝ v₁ (partialDeriv ℝ vβ‚‚ f) = partialDeriv ℝ vβ‚‚ (partialDeriv ℝ v₁ f) := by intro v₁ vβ‚‚ funext z have derivSymm : (fderiv ℝ (fun w => fderiv ℝ f w) z) v₁ vβ‚‚ = (fderiv ℝ (fun w => fderiv ℝ f w) z) vβ‚‚ v₁ := by let f' := fderiv ℝ f have hβ‚€ : βˆ€ y, HasFDerivAt f (f' y) y := by intro y exact DifferentiableAt.hasFDerivAt ((h.differentiable one_le_two) y) let f'' := (fderiv ℝ f' z) have h₁ : HasFDerivAt f' f'' z := by apply DifferentiableAt.hasFDerivAt apply (contDiff_succ_iff_fderiv.1 h).right.differentiable (Submonoid.oneLE.proof_2 β„•βˆž) apply second_derivative_symmetric hβ‚€ h₁ v₁ vβ‚‚ rw [← partialDeriv_fderiv ℝ h z vβ‚‚ v₁] rw [derivSymm] rw [partialDeriv_fderiv ℝ h z v₁ vβ‚‚] theorem partialDeriv_commOn {E : Type*} [NormedAddCommGroup E] [NormedSpace ℝ E] {F : Type*} [NormedAddCommGroup F] [NormedSpace ℝ F] {s : Set E} {f : E β†’ F} (hs : IsOpen s) (h : ContDiffOn ℝ 2 f s) : βˆ€ v₁ vβ‚‚ : E, βˆ€ z ∈ s, partialDeriv ℝ v₁ (partialDeriv ℝ vβ‚‚ f) z = partialDeriv ℝ vβ‚‚ (partialDeriv ℝ v₁ f) z := by intro v₁ vβ‚‚ z hz have derivSymm : (fderiv ℝ (fun w => fderiv ℝ f w) z) v₁ vβ‚‚ = (fderiv ℝ (fun w => fderiv ℝ f w) z) vβ‚‚ v₁ := by let f' := fderiv ℝ f have hβ‚€ : βˆ€ y ∈ s, HasFDerivAt f (f' y) y := by intro y hy apply DifferentiableAt.hasFDerivAt apply DifferentiableOn.differentiableAt _ (IsOpen.mem_nhds hs hy) apply h.differentiableOn one_le_two let f'' := (fderiv ℝ f' z) have h₁ : HasFDerivAt f' f'' z := by apply DifferentiableAt.hasFDerivAt apply DifferentiableOn.differentiableAt _ (IsOpen.mem_nhds hs hz) apply ContDiffOn.differentiableOn _ (Submonoid.oneLE.proof_2 β„•βˆž) exact ((contDiffOn_succ_iff_fderiv_of_isOpen hs).1 h).2 have hβ‚€' : βˆ€αΆ  (y : E) in nhds z, HasFDerivAt f (f' y) y := by apply eventually_nhds_iff.mpr use s exact second_derivative_symmetric_of_eventually hβ‚€' h₁ v₁ vβ‚‚ rw [← partialDeriv_fderivOn ℝ hs h vβ‚‚ v₁ z hz] rw [derivSymm] rw [← partialDeriv_fderivOn ℝ hs h v₁ vβ‚‚ z hz]