Created
May 3, 2026 10:25
-
-
Save kim-em/f796143690a6c9ba2312f7a7956efbdc to your computer and use it in GitHub Desktop.
lean-eval Aristotle (Harmonic) submission for heat_kernel_solves_heat_equation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import ChallengeDeps | |
| open LeanEval.Analysis.ODE | |
| open Real MeasureTheory | |
| theorem heat_kernel_solves_heat_equation (f : ℝ → ℝ) (hf_cont : Continuous f) (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) : | |
| -- The PDE on (0, ∞) × ℝ. | |
| (∀ t : ℝ, 0 < t → ∀ x : ℝ, ∃ ux : ℝ → ℝ, ∃ uxx : ℝ, | |
| (∀ y : ℝ, HasDerivAt (fun z => heatSolution f t z) (ux y) y) ∧ | |
| HasDerivAt ux uxx x ∧ | |
| HasDerivAt (fun s => heatSolution f s x) uxx t) ∧ | |
| -- Initial condition recovered as a one-sided limit at t = 0. | |
| (∀ x : ℝ, | |
| Filter.Tendsto (fun t : ℝ => heatSolution f t x) | |
| (nhdsWithin (0 : ℝ) (Set.Ioi 0)) (nhds (f x))) := by | |
| sorry |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "challenge_module": "Challenge", | |
| "solution_module": "Solution", | |
| "theorem_names": [ | |
| "heat_kernel_solves_heat_equation" | |
| ], | |
| "permitted_axioms": [ | |
| "propext", | |
| "Quot.sound", | |
| "Classical.choice" | |
| ], | |
| "enable_nanoda": false | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| namespace Submission.Helpers | |
| end Submission.Helpers |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name = "heat_kernel_solves_heat_equation" | |
| testDriver = "workspace_test" | |
| defaultTargets = ["Challenge", "Solution", "Submission"] | |
| [leanOptions] | |
| autoImplicit = false | |
| [[require]] | |
| name = "mathlib" | |
| git = "https://github.com/leanprover-community/mathlib4.git" | |
| rev = "5450b53e5ddc" | |
| [[lean_lib]] | |
| name = "ChallengeDeps" | |
| [[lean_lib]] | |
| name = "Challenge" | |
| [[lean_lib]] | |
| name = "Solution" | |
| [[lean_lib]] | |
| name = "Submission" | |
| [[lean_exe]] | |
| name = "workspace_test" | |
| root = "WorkspaceTest" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| leanprover/lean4:v4.30.0-rc2 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import ChallengeDeps | |
| import Submission | |
| open LeanEval.Analysis.ODE | |
| open Real MeasureTheory | |
| theorem heat_kernel_solves_heat_equation (f : ℝ → ℝ) (hf_cont : Continuous f) (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) : | |
| -- The PDE on (0, ∞) × ℝ. | |
| (∀ t : ℝ, 0 < t → ∀ x : ℝ, ∃ ux : ℝ → ℝ, ∃ uxx : ℝ, | |
| (∀ y : ℝ, HasDerivAt (fun z => heatSolution f t z) (ux y) y) ∧ | |
| HasDerivAt ux uxx x ∧ | |
| HasDerivAt (fun s => heatSolution f s x) uxx t) ∧ | |
| -- Initial condition recovered as a one-sided limit at t = 0. | |
| (∀ x : ℝ, | |
| Filter.Tendsto (fun t : ℝ => heatSolution f t x) | |
| (nhdsWithin (0 : ℝ) (Set.Ioi 0)) (nhds (f x))) := by | |
| exact Submission.heat_kernel_solves_heat_equation f hf_cont hf_bdd |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import ChallengeDeps | |
| open LeanEval.Analysis.ODE | |
| open Real MeasureTheory | |
| namespace Submission | |
| -- ============================================================================ | |
| -- Helper lemmas | |
| -- ============================================================================ | |
| noncomputable section | |
| open Filter Topology | |
| /-- When `t > 0`, the `if` in heatKernel drops away. -/ | |
| lemma heatKernel_of_pos {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| heatKernel t x = (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-(x ^ 2 / (4 * t))) := by | |
| simp [heatKernel, not_le.mpr ht] | |
| /-- The prefactor `(√(4πt))⁻¹` is positive for `t > 0`. -/ | |
| lemma heatKernel_prefactor_pos {t : ℝ} (ht : 0 < t) : | |
| 0 < (Real.sqrt (4 * Real.pi * t))⁻¹ := by | |
| positivity | |
| /-- `heatKernel t x ≥ 0` for `t > 0`. -/ | |
| lemma heatKernel_nonneg {t : ℝ} (ht : 0 < t) (x : ℝ) : 0 ≤ heatKernel t x := by | |
| rw [heatKernel_of_pos ht] | |
| positivity | |
| /- | |
| The heat kernel integrates to 1 over ℝ. | |
| -/ | |
| lemma heatKernel_integral_one {t : ℝ} (ht : 0 < t) : | |
| ∫ x, heatKernel t x = 1 := by | |
| rw [ MeasureTheory.integral_congr_ae, MeasureTheory.integral_const_mul ]; | |
| case r => exact ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹; | |
| rotate_left; | |
| exact fun x => Real.exp ( -x ^ 2 / ( 4 * t ) ); | |
| · filter_upwards [ ] with x using by rw [ heatKernel_of_pos ht ] ; ring; | |
| · rw [ inv_mul_eq_div, div_eq_iff ] <;> first | positivity | have := integral_gaussian ( 1 / ( 4 * t ) ) ; simp_all +decide [ div_eq_inv_mul ] ; | |
| ring | |
| /-- The heat kernel (for fixed t > 0) is continuous in x. -/ | |
| lemma heatKernel_continuous {t : ℝ} (ht : 0 < t) : Continuous (heatKernel t) := by | |
| have : heatKernel t = fun x => (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-(x ^ 2 / (4 * t))) := | |
| funext (heatKernel_of_pos ht) | |
| rw [this]; fun_prop | |
| /-- The heat kernel is integrable (for fixed t > 0). -/ | |
| lemma heatKernel_integrable {t : ℝ} (ht : 0 < t) : Integrable (heatKernel t) volume := | |
| integrable_of_integral_eq_one (heatKernel_integral_one ht) | |
| /- | |
| The integrand `heatKernel t (x - ·) * f ·` is integrable when `f` is bounded and continuous. | |
| -/ | |
| lemma heatSolution_integrable {f : ℝ → ℝ} {t : ℝ} (ht : 0 < t) | |
| (hf_cont : Continuous f) (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) : | |
| Integrable (fun y => heatKernel t (x - y) * f y) volume := by | |
| have h_integrable : Integrable (fun y => heatKernel t (x - y) * hf_bdd.choose) volume := by | |
| exact MeasureTheory.Integrable.mul_const ( MeasureTheory.Integrable.comp_sub_left ( heatKernel_integrable ht ) x ) _; | |
| refine' h_integrable.norm.mono' _ _; | |
| · exact MeasureTheory.AEStronglyMeasurable.mul ( by exact Continuous.aestronglyMeasurable ( by exact heatKernel_continuous ht |> Continuous.comp <| continuous_const.sub continuous_id' ) ) hf_cont.aestronglyMeasurable; | |
| · simp +zetaDelta at *; | |
| filter_upwards [ ] with y using mul_le_mul_of_nonneg_left ( le_trans ( hf_bdd.choose_spec y ) ( le_abs_self _ ) ) ( abs_nonneg _ ) | |
| /- | |
| After substitution u = (x-y)/√(4t), the heat solution becomes | |
| `∫ u, (1/√π) exp(-u²) f(x - u√(4t))`. | |
| -/ | |
| lemma heatSolution_substitution {f : ℝ → ℝ} {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| heatSolution f t x = | |
| ∫ u, (Real.sqrt Real.pi)⁻¹ * Real.exp (-(u ^ 2)) * f (x - u * Real.sqrt (4 * t)) := by | |
| -- We'll use the substitution $u = \frac{x - y}{\sqrt{4t}}$ to transform the integral. | |
| have h_subst : ∀ {g : ℝ → ℝ}, ∫ y, g y = ∫ u, g (x - u * Real.sqrt (4 * t)) * Real.sqrt (4 * t) := by | |
| intro g; rw [ MeasureTheory.integral_mul_const ] ; rw [ MeasureTheory.Measure.integral_comp_mul_right ( fun u => g ( x - u ) ) ] ; norm_num [ ht.le ] ; | |
| rw [ abs_of_nonneg ( Real.sqrt_nonneg _ ), MeasureTheory.integral_sub_left_eq_self ] ; ring ; norm_num [ ht.le, ht.ne' ]; | |
| convert h_subst using 3; | |
| unfold heatKernel; norm_num [ ht.le ] ; ring; | |
| grind | |
| /- | |
| `(√π)⁻¹ exp(-u²)` integrates to 1. | |
| -/ | |
| lemma gauss_normalized : | |
| ∫ u : ℝ, (Real.sqrt Real.pi)⁻¹ * Real.exp (-(u ^ 2)) = 1 := by | |
| rw [ MeasureTheory.integral_const_mul, show ∫ u : ℝ, Real.exp ( -u ^ 2 ) = Real.sqrt Real.pi by simpa using integral_gaussian ( 1 : ℝ ) ] ; norm_num [ ne_of_gt, Real.pi_pos ] | |
| /- | |
| ============================================================================ | |
| Part 2: Initial condition | |
| ============================================================================ | |
| As `t → 0⁺`, `heatSolution f t x → f x`. | |
| -/ | |
| lemma heatSolution_initial (f : ℝ → ℝ) (hf_cont : Continuous f) | |
| (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) (x : ℝ) : | |
| Tendsto (fun t => heatSolution f t x) | |
| (nhdsWithin (0 : ℝ) (Set.Ioi 0)) (nhds (f x)) := by | |
| -- Use the substitution $u = \frac{x - y}{\sqrt{4t}}$ to rewrite the integral. | |
| suffices h_subst : Filter.Tendsto (fun t => ∫ u, (Real.sqrt Real.pi)⁻¹ * Real.exp (-(u ^ 2)) * f (x - u * Real.sqrt (4 * t))) (𝓝[>] 0) (𝓝 (f x)) by | |
| exact h_subst.congr' ( Filter.eventuallyEq_of_mem self_mem_nhdsWithin fun t ht => by rw [ heatSolution_substitution ht ] ); | |
| -- Apply the dominated convergence theorem. | |
| have h_dominated : Filter.Tendsto (fun t => ∫ u, (Real.sqrt Real.pi)⁻¹ * Real.exp (-(u ^ 2)) * f (x - u * Real.sqrt (4 * t))) (𝓝[>] 0) (𝓝 (∫ u, (Real.sqrt Real.pi)⁻¹ * Real.exp (-(u ^ 2)) * f x)) := by | |
| refine' MeasureTheory.tendsto_integral_filter_of_dominated_convergence _ _ _ _ _; | |
| refine' fun u => ( Real.sqrt Real.pi ) ⁻¹ * Real.exp ( -u ^ 2 ) * hf_bdd.choose; | |
| · exact Filter.Eventually.of_forall fun t => Continuous.aestronglyMeasurable ( by continuity ); | |
| · filter_upwards [ self_mem_nhdsWithin ] with t ht using Filter.Eventually.of_forall fun u => by simpa [ abs_mul, abs_inv, abs_of_nonneg ( Real.sqrt_nonneg _ ), abs_of_nonneg ( Real.exp_pos _ |> le_of_lt ) ] using mul_le_mul_of_nonneg_left ( hf_bdd.choose_spec _ ) ( by positivity ) ; | |
| · exact MeasureTheory.Integrable.mul_const ( MeasureTheory.Integrable.const_mul ( by simpa using ( integrable_exp_neg_mul_sq ( by norm_num : ( 0 : ℝ ) < 1 ) ) ) _ ) _; | |
| · exact Filter.Eventually.of_forall fun u => tendsto_const_nhds.mul ( hf_cont.continuousAt.tendsto.comp <| tendsto_nhdsWithin_of_tendsto_nhds <| Continuous.tendsto' ( by continuity ) _ _ <| by norm_num ); | |
| convert h_dominated using 2 ; norm_num [ MeasureTheory.integral_const_mul, MeasureTheory.integral_mul_const, gauss_normalized ]; | |
| have := integral_gaussian ( 1 : ℝ ) ; norm_num at this ; rw [ this ] ; ring ; norm_num [ Real.sqrt_ne_zero'.mpr Real.pi_pos ] | |
| -- ============================================================================ | |
| -- Part 1: PDE — differentiation under the integral | |
| -- ============================================================================ | |
| /-- Derivative of heatKernel w.r.t. x -/ | |
| noncomputable def heatKernel_dx (t : ℝ) (x : ℝ) : ℝ := | |
| if t ≤ 0 then 0 | |
| else (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-(x ^ 2 / (4 * t))) * (-(x / (2 * t))) | |
| /-- Second derivative of heatKernel w.r.t. x -/ | |
| noncomputable def heatKernel_dxx (t : ℝ) (x : ℝ) : ℝ := | |
| if t ≤ 0 then 0 | |
| else (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-(x ^ 2 / (4 * t))) * | |
| (x ^ 2 / (4 * t ^ 2) - 1 / (2 * t)) | |
| /- | |
| `heatKernel t` has derivative `heatKernel_dx t` at `x`. | |
| -/ | |
| lemma heatKernel_hasDerivAt_x {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| HasDerivAt (heatKernel t) (heatKernel_dx t x) x := by | |
| convert HasDerivAt.congr_of_eventuallyEq _ ?_ using 1; | |
| exact fun x => ( Real.sqrt ( t * 4 * Real.pi ) ) ⁻¹ * Real.exp ( - ( x ^ 2 / ( 4 * t ) ) ); | |
| · convert HasDerivAt.const_mul _ ( HasDerivAt.exp ( HasDerivAt.neg ( HasDerivAt.div_const ( hasDerivAt_pow 2 x ) _ ) ) ) using 1 ; ring; | |
| unfold heatKernel_dx; norm_num [ ht.le ] ; ring; | |
| grind; | |
| · filter_upwards [ ] using fun x => by unfold heatKernel; rw [ if_neg ( by linarith ) ] ; ring | |
| /- | |
| `heatKernel_dx t` has derivative `heatKernel_dxx t` at `x`. | |
| -/ | |
| lemma heatKernel_hasDerivAt_xx {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| HasDerivAt (heatKernel_dx t) (heatKernel_dxx t x) x := by | |
| convert HasDerivAt.congr_of_eventuallyEq _ ?_ using 1; | |
| exact fun x => ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ * Real.exp ( - ( x ^ 2 / ( 4 * t ) ) ) * ( - ( x / ( 2 * t ) ) ); | |
| · convert HasDerivAt.mul ( HasDerivAt.mul ( hasDerivAt_const _ _ ) ( HasDerivAt.exp ( HasDerivAt.neg ( HasDerivAt.div_const ( hasDerivAt_pow 2 x ) _ ) ) ) ) ( HasDerivAt.neg ( HasDerivAt.div_const ( hasDerivAt_id x ) _ ) ) using 1 ; norm_num [ heatKernel_dxx ] ; ring; | |
| grind; | |
| · exact Filter.eventuallyEq_of_mem ( Metric.ball_mem_nhds _ ht ) fun y hy => if_neg <| not_le_of_gt <| by linarith [ abs_lt.mp hy.out ] ; | |
| /- | |
| The first spatial derivative of heatSolution: differentiate under the integral. | |
| -/ | |
| lemma heatSolution_hasDerivAt_x (f : ℝ → ℝ) (hf_cont : Continuous f) | |
| (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| HasDerivAt (fun z => heatSolution f t z) | |
| (∫ y, heatKernel_dx t (x - y) * f y) x := by | |
| -- By the mean value theorem, we can write the difference quotient as an integral. | |
| have h_mean_value : ∀ h ≠ 0, (heatSolution f t (x + h) - heatSolution f t x) / h = ∫ y, (∫ u in (0 : ℝ)..1, heatKernel_dx t (x - y + u * h)) * f y := by | |
| intro h hh | |
| have h_mean_value : ∀ y, (heatKernel t (x + h - y) - heatKernel t (x - y)) = h * ∫ u in (0 : ℝ)..1, heatKernel_dx t (x - y + u * h) := by | |
| intro y | |
| have h_mean_value : ∀ a b, ∫ u in a..b, heatKernel_dx t (x - y + u * h) = (1 / h) * (heatKernel t (x - y + b * h) - heatKernel t (x - y + a * h)) := by | |
| intro a b; rw [ intervalIntegral.integral_comp_mul_right ( fun u => heatKernel_dx t ( x - y + u ) ) ] <;> norm_num [ hh ] ; ring; | |
| rw [ intervalIntegral.integral_eq_sub_of_hasDerivAt ]; | |
| · exact fun u hu => heatKernel_hasDerivAt_x ht u; | |
| · apply_rules [ Continuous.intervalIntegrable ]; | |
| exact Continuous.congr ( show Continuous fun x => ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ * Real.exp ( - ( x ^ 2 / ( 4 * t ) ) ) * ( - ( x / ( 2 * t ) ) ) from by continuity ) fun x => by unfold heatKernel_dx; aesop; | |
| grind; | |
| have h_integral_mean_value : ∫ y, (heatKernel t (x + h - y) - heatKernel t (x - y)) * f y = h * ∫ y, (∫ u in (0 : ℝ)..1, heatKernel_dx t (x - y + u * h)) * f y := by | |
| simp +decide only [h_mean_value, mul_assoc, integral_const_mul]; | |
| convert congr_arg ( fun z => z / h ) h_integral_mean_value using 1; | |
| · simp +decide only [heatSolution, sub_mul]; | |
| rw [ MeasureTheory.integral_sub ]; | |
| · exact?; | |
| · exact?; | |
| · rw [ mul_div_cancel_left₀ _ hh ]; | |
| -- To apply the dominated convergence theorem, we need to show that the integrand is dominated by an integrable function. | |
| have h_dominate : ∀ h : ℝ, ∀ y : ℝ, |(∫ u in (0 : ℝ)..1, heatKernel_dx t (x - y + u * h)) * f y| ≤ (∫ u in (0 : ℝ)..1, |heatKernel_dx t (x - y + u * h)|) * |f y| := by | |
| intro h y; rw [ intervalIntegral.integral_of_le zero_le_one, intervalIntegral.integral_of_le zero_le_one ] ; simp +decide [ abs_mul, MeasureTheory.integral_const_mul ] ; | |
| exact mul_le_mul_of_nonneg_right ( MeasureTheory.norm_integral_le_integral_norm ( _ : ℝ → ℝ ) ) ( abs_nonneg _ ); | |
| -- To apply the dominated convergence theorem, we need to show that the integrand is dominated by an integrable function. We'll use the fact that |heatKernel_dx t (x - y + u * h)| is bounded. | |
| have h_bound : ∃ C : ℝ, ∀ y : ℝ, ∀ h : ℝ, |h| ≤ 1 → ∫ u in (0 : ℝ)..1, |heatKernel_dx t (x - y + u * h)| ≤ C * (1 + |x - y|) * Real.exp (-(x - y)^2 / (8 * t)) := by | |
| -- We'll use the fact that |heatKernel_dx t (x - y + u * h)| is bounded by a constant times (1 + |x - y|) * exp(-(x - y)^2 / (8 * t)). | |
| have h_bound : ∃ C : ℝ, ∀ y : ℝ, ∀ u : ℝ, |u| ≤ 1 → |heatKernel_dx t (x - y + u)| ≤ C * (1 + |x - y|) * Real.exp (-(x - y)^2 / (8 * t)) := by | |
| -- We'll use the fact that |heatKernel_dx t (x - y + u)| is bounded by a constant times (1 + |x - y|) * exp(-(x - y)^2 / (8 * t)). This follows from the properties of the Gaussian function and the fact that |u| ≤ 1. | |
| have h_bound : ∃ C : ℝ, ∀ y : ℝ, ∀ u : ℝ, |u| ≤ 1 → |(x - y + u) * Real.exp (-(x - y + u)^2 / (4 * t))| ≤ C * (1 + |x - y|) * Real.exp (-(x - y)^2 / (8 * t)) := by | |
| use 2 * Real.exp (1 / (4 * t)); | |
| intro y u hu | |
| have h_exp_bound : Real.exp (-(x - y + u)^2 / (4 * t)) ≤ Real.exp (1 / (4 * t)) * Real.exp (-(x - y)^2 / (8 * t)) := by | |
| rw [ ← Real.exp_add ] ; ring_nf ; norm_num; | |
| nlinarith [ sq_nonneg ( x - y - 2 * u ), sq_nonneg ( x - y + 2 * u ), abs_le.mp hu, inv_pos.mpr ht, mul_inv_cancel₀ ht.ne' ]; | |
| rw [ abs_mul, abs_of_nonneg ( Real.exp_pos _ |> LT.lt.le ) ]; | |
| refine le_trans ( mul_le_mul_of_nonneg_right ( show |x - y + u| ≤ 1 + |x - y| by cases abs_cases ( x - y + u ) <;> cases abs_cases ( x - y ) <;> linarith [ abs_le.mp hu ] ) ( Real.exp_nonneg _ ) ) ?_; | |
| nlinarith [ show 0 ≤ ( 1 + |x - y| ) * Real.exp ( 1 / ( 4 * t ) ) * Real.exp ( - ( x - y ) ^ 2 / ( 8 * t ) ) by positivity, show 0 ≤ ( 1 + |x - y| ) * Real.exp ( - ( x - y + u ) ^ 2 / ( 4 * t ) ) by positivity, Real.exp_pos ( 1 / ( 4 * t ) ), Real.exp_pos ( - ( x - y ) ^ 2 / ( 8 * t ) ), Real.exp_pos ( - ( x - y + u ) ^ 2 / ( 4 * t ) ) ]; | |
| unfold heatKernel_dx; | |
| obtain ⟨ C, hC ⟩ := h_bound; | |
| use C * (Real.sqrt (4 * Real.pi * t))⁻¹ * (1 / (2 * t)); | |
| intro y u hu; split_ifs <;> simp_all +decide [ abs_mul, abs_div, abs_neg, abs_of_pos ]; | |
| · linarith; | |
| · convert mul_le_mul_of_nonneg_right ( hC y u hu ) ( show 0 ≤ ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ * ( t⁻¹ * 2⁻¹ ) by positivity ) using 1 <;> ring; | |
| rw [ abs_of_nonneg ( Real.sqrt_nonneg _ ) ] ; ring; | |
| obtain ⟨ C, hC ⟩ := h_bound; | |
| use C; | |
| intro y h hh; rw [ intervalIntegral.integral_of_le zero_le_one ] ; refine' le_trans ( MeasureTheory.integral_mono_of_nonneg _ _ _ ) _; | |
| refine' fun u => C * ( 1 + |x - y| ) * Real.exp ( - ( x - y ) ^ 2 / ( 8 * t ) ); | |
| · exact Filter.Eventually.of_forall fun _ => abs_nonneg _; | |
| · fun_prop; | |
| · filter_upwards [ MeasureTheory.ae_restrict_mem measurableSet_Ioc ] with u hu using hC y ( u * h ) ( by rw [ abs_mul ] ; exact mul_le_one₀ ( abs_le.mpr ⟨ by linarith [ hu.1 ], by linarith [ hu.2 ] ⟩ ) ( abs_nonneg _ ) hh ); | |
| · norm_num; | |
| -- Using the bound, we can show that the integrand is dominated by an integrable function. | |
| obtain ⟨C, hC⟩ := h_bound; | |
| have h_integrable : MeasureTheory.Integrable (fun y => C * (1 + |x - y|) * Real.exp (-(x - y)^2 / (8 * t)) * |f y|) MeasureTheory.volume := by | |
| have h_integrable : MeasureTheory.Integrable (fun y => (1 + |x - y|) * Real.exp (-(x - y)^2 / (8 * t))) MeasureTheory.volume := by | |
| have h_integrable : MeasureTheory.Integrable (fun y => (1 + |y|) * Real.exp (-y^2 / (8 * t))) MeasureTheory.volume := by | |
| have h_integrable : MeasureTheory.Integrable (fun y => |y| * Real.exp (-y^2 / (8 * t))) MeasureTheory.volume := by | |
| have := @integrable_rpow_mul_exp_neg_mul_sq; | |
| specialize @this ( 1 / ( 8 * t ) ) ( by positivity ) 1 ; norm_num at this; | |
| convert this.norm using 2 ; norm_num ; ring; | |
| norm_num; | |
| simp_all +decide [ add_mul ]; | |
| simpa [ div_eq_inv_mul ] using ( integrable_exp_neg_mul_sq ( by positivity ) ); | |
| convert h_integrable.comp_sub_left x using 1; | |
| have h_integrable : MeasureTheory.Integrable (fun y => (1 + |x - y|) * Real.exp (-(x - y)^2 / (8 * t)) * |f y|) MeasureTheory.volume := by | |
| refine' h_integrable.norm.mul_const _ |> fun h => h.mono' _ _; | |
| exact hf_bdd.choose; | |
| · exact MeasureTheory.AEStronglyMeasurable.mul ( h_integrable.aestronglyMeasurable ) ( hf_cont.abs.aestronglyMeasurable ); | |
| · filter_upwards [ ] using fun y => by simpa [ abs_mul ] using mul_le_mul_of_nonneg_left ( hf_bdd.choose_spec y ) ( by positivity ) ; | |
| simpa only [ mul_assoc ] using h_integrable.const_mul C; | |
| have h_dominated_convergence : Filter.Tendsto (fun h => ∫ y, (∫ u in (0 : ℝ)..1, heatKernel_dx t (x - y + u * h)) * f y) (nhdsWithin 0 {0}ᶜ) (nhds (∫ y, heatKernel_dx t (x - y) * f y)) := by | |
| refine' MeasureTheory.tendsto_integral_filter_of_dominated_convergence _ _ _ _ _; | |
| use fun y => C * ( 1 + |x - y| ) * Real.exp ( - ( x - y ) ^ 2 / ( 8 * t ) ) * |f y|; | |
| · refine' Filter.eventually_of_mem self_mem_nhdsWithin fun n hn => Continuous.aestronglyMeasurable _; | |
| unfold heatKernel_dx; | |
| split_ifs <;> norm_num ; continuity; | |
| fun_prop; | |
| · filter_upwards [ self_mem_nhdsWithin, mem_nhdsWithin_of_mem_nhds ( Metric.ball_mem_nhds _ zero_lt_one ) ] with n hn hn' using Filter.Eventually.of_forall fun y => le_trans ( h_dominate n y ) ( mul_le_mul_of_nonneg_right ( hC y n ( by simpa using hn'.out.le ) ) ( abs_nonneg _ ) ); | |
| · exact h_integrable; | |
| · refine' Filter.Eventually.of_forall fun y => _; | |
| refine' Filter.Tendsto.mul _ tendsto_const_nhds; | |
| have h_cont : Continuous (fun n => ∫ u in (0 : ℝ)..1, heatKernel_dx t (x - y + u * n)) := by | |
| have h_cont : Continuous (fun n => ∫ u in (0 : ℝ)..1, (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-( (x - y + u * n) ^ 2 / (4 * t))) * (-( (x - y + u * n) / (2 * t)))) := by | |
| fun_prop; | |
| convert h_cont using 1; | |
| ext n; refine' intervalIntegral.integral_congr fun u hu => _; unfold heatKernel_dx; aesop; | |
| convert h_cont.continuousWithinAt.tendsto using 2 ; norm_num; | |
| rw [ hasDerivAt_iff_tendsto_slope_zero ]; | |
| exact h_dominated_convergence.congr' ( by filter_upwards [ self_mem_nhdsWithin ] with h hh using by rw [ ← h_mean_value h hh ] ; norm_num [ div_eq_inv_mul ] ) | |
| /- | |
| The second spatial derivative of heatSolution. | |
| -/ | |
| set_option maxHeartbeats 800000 in | |
| lemma heatSolution_hasDerivAt_xx (f : ℝ → ℝ) (hf_cont : Continuous f) | |
| (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| HasDerivAt (fun z => ∫ y, heatKernel_dx t (z - y) * f y) | |
| (∫ y, heatKernel_dxx t (x - y) * f y) x := by | |
| rw [ hasDerivAt_iff_tendsto_slope_zero ]; | |
| -- By Fubini's theorem, we can interchange the order of integration. | |
| have h_fubini : ∀ h : ℝ, h ≠ 0 → ∫ y, (∫ u in (0 : ℝ)..1, heatKernel_dxx t (x + u * h - y) * f y) = ∫ u in (0 : ℝ)..1, ∫ y, heatKernel_dxx t (x + u * h - y) * f y := by | |
| intro h hh; rw [ intervalIntegral.integral_of_le zero_le_one ] ; rw [ MeasureTheory.integral_integral_swap ] ; | |
| · norm_num [ intervalIntegral.integral_of_le zero_le_one ]; | |
| · -- The function $heatKernel_dxx t (x + u * h - y) * f y$ is integrable because $heatKernel_dxx$ is bounded and $f$ is bounded. | |
| have h_integrable : ∀ u ∈ Set.Icc (0 : ℝ) 1, Integrable (fun y => heatKernel_dxx t (x + u * h - y) * f y) volume := by | |
| intro u hu | |
| have h_integrable : Integrable (fun y => heatKernel_dxx t (x + u * h - y)) volume := by | |
| have h_integrable : Integrable (fun y => heatKernel_dxx t y) volume := by | |
| have h_integrable : Integrable (fun y => (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-(y ^ 2 / (4 * t))) * (y ^ 2 / (4 * t ^ 2) - 1 / (2 * t))) volume := by | |
| have h_integrable : Integrable (fun y => Real.exp (-(y ^ 2 / (4 * t))) * y ^ 2) volume := by | |
| have := @integrable_rpow_mul_exp_neg_mul_sq; | |
| convert @this ( 1 / ( 4 * t ) ) ( by positivity ) 2 ( by norm_num ) using 1 ; norm_num ; ring; | |
| ac_rfl; | |
| have h_integrable : Integrable (fun y => Real.exp (-(y ^ 2 / (4 * t)))) volume := by | |
| simpa [ div_eq_inv_mul ] using ( integrable_exp_neg_mul_sq ( by positivity ) ); | |
| convert ‹Integrable ( fun y => Real.exp ( - ( y ^ 2 / ( 4 * t ) ) ) * y ^ 2 ) volume›.const_mul ( ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ / ( 4 * t ^ 2 ) ) |> fun h => h.sub ( h_integrable.const_mul ( ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ / ( 2 * t ) ) ) using 2 ; ring; | |
| norm_num ; ring; | |
| convert h_integrable using 1; | |
| ext y; unfold heatKernel_dxx; aesop; | |
| exact h_integrable.comp_sub_left _; | |
| refine' h_integrable.norm.mul_const _ |> fun h => h.mono' _ _; | |
| exact hf_bdd.choose; | |
| · exact h_integrable.1.mul ( hf_cont.aestronglyMeasurable ); | |
| · filter_upwards [ ] using fun y => by rw [ norm_mul ] ; exact mul_le_mul_of_nonneg_left ( hf_bdd.choose_spec y ) ( norm_nonneg _ ) ; | |
| rw [ MeasureTheory.integrable_prod_iff ]; | |
| · have h_integrable : ∀ u ∈ Set.Icc (0 : ℝ) 1, ∫ y, ‖heatKernel_dxx t (x + u * h - y) * f y‖ ≤ (Real.sqrt (4 * Real.pi * t))⁻¹ * (1 / (2 * t)) * hf_bdd.choose * ∫ y, Real.exp (-( (x + u * h - y) ^ 2 / (4 * t) )) * (1 + (x + u * h - y) ^ 2 / (2 * t)) := by | |
| intro u hu | |
| have h_bound : ∀ y, ‖heatKernel_dxx t (x + u * h - y) * f y‖ ≤ (Real.sqrt (4 * Real.pi * t))⁻¹ * (1 / (2 * t)) * hf_bdd.choose * Real.exp (-( (x + u * h - y) ^ 2 / (4 * t) )) * (1 + (x + u * h - y) ^ 2 / (2 * t)) := by | |
| intro y | |
| have h_bound : ‖heatKernel_dxx t (x + u * h - y)‖ ≤ (Real.sqrt (4 * Real.pi * t))⁻¹ * (1 / (2 * t)) * Real.exp (-( (x + u * h - y) ^ 2 / (4 * t) )) * (1 + (x + u * h - y) ^ 2 / (2 * t)) := by | |
| unfold heatKernel_dxx; | |
| split_ifs <;> norm_num; | |
| · grind; | |
| · rw [ abs_of_nonneg ( Real.sqrt_nonneg _ ) ]; | |
| field_simp; | |
| rw [ abs_div, abs_of_nonneg ( by positivity : ( 0 : ℝ ) ≤ 4 * t ^ 2 * 2 ) ]; | |
| rw [ mul_div, div_le_iff₀ ] <;> cases abs_cases ( ( x + u * h - y ) ^ 2 * 2 - 4 * t ) <;> nlinarith [ sq_nonneg ( x + u * h - y ), mul_pos ht ht ]; | |
| rw [ norm_mul ]; | |
| refine le_trans ( mul_le_mul_of_nonneg_right h_bound <| norm_nonneg _ ) ?_; | |
| convert mul_le_mul_of_nonneg_left ( hf_bdd.choose_spec y ) ( show 0 ≤ ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ * ( 1 / ( 2 * t ) ) * Real.exp ( - ( ( x + u * h - y ) ^ 2 / ( 4 * t ) ) ) * ( 1 + ( x + u * h - y ) ^ 2 / ( 2 * t ) ) by positivity ) using 1 ; ring; | |
| rw [ ← MeasureTheory.integral_const_mul ]; | |
| refine' MeasureTheory.integral_mono_of_nonneg _ _ _; | |
| · exact Filter.Eventually.of_forall fun y => norm_nonneg _; | |
| · have h_integrable : Integrable (fun y => Real.exp (-( (x + u * h - y) ^ 2 / (4 * t) )) * (1 + (x + u * h - y) ^ 2 / (2 * t))) volume := by | |
| have h_integrable : Integrable (fun y => Real.exp (-(y ^ 2 / (4 * t))) * (1 + y ^ 2 / (2 * t))) volume := by | |
| have h_gauss_integrable : Integrable (fun y => Real.exp (-(y ^ 2 / (4 * t))) * y ^ 2) volume := by | |
| have := @integrable_rpow_mul_exp_neg_mul_sq; | |
| convert @this ( 1 / ( 4 * t ) ) ( by positivity ) 2 ( by norm_num ) using 1 ; norm_num ; ring; | |
| ac_rfl; | |
| convert h_gauss_integrable.div_const ( 2 * t ) |> Integrable.add <| ( integrable_exp_neg_mul_sq ( show 0 < 1 / ( 4 * t ) by positivity ) ) using 2 ; ring; | |
| norm_num ; ring; | |
| convert h_integrable.comp_sub_left ( x + u * h ) using 1; | |
| exact h_integrable.const_mul _; | |
| · filter_upwards [ ] using fun y => by simpa only [ mul_assoc ] using h_bound y; | |
| have h_integrable : ∀ u ∈ Set.Icc (0 : ℝ) 1, ∫ y, Real.exp (-( (x + u * h - y) ^ 2 / (4 * t) )) * (1 + (x + u * h - y) ^ 2 / (2 * t)) = Real.sqrt (4 * Real.pi * t) * (1 + 1 / (2 * t) * (2 * t)) := by | |
| intro u hu | |
| have h_gauss : ∫ y, Real.exp (-(y ^ 2 / (4 * t))) * (1 + y ^ 2 / (2 * t)) = Real.sqrt (4 * Real.pi * t) * (1 + 1 / (2 * t) * (2 * t)) := by | |
| have h_gauss : ∫ y, Real.exp (-(y ^ 2 / (4 * t))) * y ^ 2 = Real.sqrt (4 * Real.pi * t) * (2 * t) := by | |
| have := @integral_rpow_mul_exp_neg_mul_rpow; | |
| have h_gauss : ∫ y in Set.Ioi 0, Real.exp (-(y ^ 2 / (4 * t))) * y ^ 2 = Real.sqrt (4 * Real.pi * t) * (2 * t) / 2 := by | |
| convert @this 2 2 ( 1 / ( 4 * t ) ) ( by norm_num ) ( by norm_num ) ( by positivity ) using 1 <;> norm_num [ div_eq_inv_mul ]; | |
| · ac_rfl; | |
| · rw [ show ( 3 / 2 : ℝ ) = 1 / 2 + 1 by norm_num, Real.Gamma_add_one ( by norm_num ), Real.rpow_neg_eq_inv_rpow ] ; ring ; norm_num [ ht.le ]; | |
| rw [ show ( t * 4 ) ^ ( 3 / 2 : ℝ ) = ( t * 4 ) * Real.sqrt ( t * 4 ) by rw [ Real.sqrt_eq_rpow, ← Real.rpow_one_add' ] <;> norm_num ; positivity ] ; norm_num [ Real.Gamma_one_half_eq, ht.le ] ; ring; | |
| have h_gauss_symm : ∫ y in Set.Iic 0, Real.exp (-(y ^ 2 / (4 * t))) * y ^ 2 = Real.sqrt (4 * Real.pi * t) * (2 * t) / 2 := by | |
| rw [ ← h_gauss, ← neg_zero, ← integral_comp_neg_Iic ] ; norm_num; | |
| convert congr_arg₂ ( · + · ) h_gauss_symm h_gauss using 1; | |
| · rw [ ← MeasureTheory.setIntegral_union ] <;> norm_num; | |
| · exact ( by contrapose! h_gauss_symm; rw [ MeasureTheory.integral_undef h_gauss_symm ] ; positivity ); | |
| · exact ( by contrapose! h_gauss; rw [ MeasureTheory.integral_undef h_gauss ] ; positivity ); | |
| · ring; | |
| have h_gauss : ∫ y, Real.exp (-(y ^ 2 / (4 * t))) = Real.sqrt (4 * Real.pi * t) := by | |
| convert integral_gaussian ( 1 / ( 4 * t ) ) using 1 <;> norm_num [ div_eq_inv_mul ] ; ring; | |
| have h_gauss : ∫ y, Real.exp (-(y ^ 2 / (4 * t))) * (1 + y ^ 2 / (2 * t)) = (∫ y, Real.exp (-(y ^ 2 / (4 * t)))) + (∫ y, Real.exp (-(y ^ 2 / (4 * t))) * y ^ 2 / (2 * t)) := by | |
| rw [ ← MeasureTheory.integral_add ] ; congr ; ext y ; ring; | |
| · exact ( by contrapose! h_gauss; rw [ MeasureTheory.integral_undef h_gauss ] ; positivity ); | |
| · exact MeasureTheory.Integrable.div_const ( by exact ( by contrapose! h_gauss; rw [ MeasureTheory.integral_undef h_gauss ] at *; nlinarith [ Real.sqrt_pos.mpr ( show 0 < 4 * Real.pi * t by positivity ) ] ) ) _; | |
| simp_all +decide [ MeasureTheory.integral_div ]; | |
| grind; | |
| rw [ ← h_gauss, eq_comm, ← MeasureTheory.integral_sub_left_eq_self ]; | |
| simp +zetaDelta at *; | |
| refine' ⟨ Filter.eventually_inf_principal.mpr _, _ ⟩; | |
| · exact Filter.Eventually.of_forall fun u hu => ‹∀ u : ℝ, 0 ≤ u → u ≤ 1 → Integrable ( fun y => heatKernel_dxx t ( x + u * h - y ) * f y ) volume› u hu.1.le hu.2; | |
| · refine' MeasureTheory.Integrable.mono' _ _ _; | |
| use fun u => ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ * ( t⁻¹ * 2⁻¹ ) * hf_bdd.choose * ( Real.sqrt ( 4 * Real.pi * t ) * ( 1 + t⁻¹ * 2⁻¹ * ( 2 * t ) ) ); | |
| · fun_prop; | |
| · refine' MeasureTheory.StronglyMeasurable.aestronglyMeasurable _; | |
| refine' MeasureTheory.StronglyMeasurable.integral_prod_right _; | |
| refine' Measurable.stronglyMeasurable _; | |
| refine' Measurable.mul _ _; | |
| · refine' Measurable.abs _; | |
| refine' Measurable.ite _ _ _ <;> norm_num; | |
| fun_prop; | |
| · exact hf_cont.abs.measurable.comp measurable_snd; | |
| · filter_upwards [ MeasureTheory.ae_restrict_mem measurableSet_Ioc ] with u hu using by rw [ Real.norm_of_nonneg ( MeasureTheory.integral_nonneg fun _ => by positivity ) ] ; exact le_trans ( by solve_by_elim [ hu.1.le, hu.2 ] ) ( by rw [ h_integrable u hu.1.le hu.2 ] ) ; | |
| · refine' Measurable.aestronglyMeasurable _; | |
| refine' Measurable.mul _ _; | |
| · refine' Measurable.ite _ _ _ <;> norm_num; | |
| fun_prop; | |
| · exact hf_cont.measurable.comp measurable_snd; | |
| -- By the properties of the heat kernel, we know that $\int_{-\infty}^{\infty} \text{heatKernel}_{xx}(t, x-y) f(y) \, dy$ is continuous in $x$. | |
| have h_cont : Continuous (fun x => ∫ y, heatKernel_dxx t (x - y) * f y) := by | |
| -- By the properties of the heat kernel, we know that $\int_{-\infty}^{\infty} \text{heatKernel}_{xx}(t, x-y) f(y) \, dy$ is continuous in $x$ because the heat kernel is continuous and the integral of a continuous function is continuous. | |
| have h_cont : Continuous (fun x => ∫ y, heatKernel_dxx t y * f (x - y)) := by | |
| refine' continuous_iff_continuousAt.mpr _; | |
| intro x; | |
| refine' MeasureTheory.tendsto_integral_filter_of_dominated_convergence _ _ _ _ _; | |
| use fun y => |heatKernel_dxx t y| * hf_bdd.choose; | |
| · refine' Filter.Eventually.of_forall fun n => MeasureTheory.AEStronglyMeasurable.mul _ _; | |
| · refine' Measurable.aestronglyMeasurable _; | |
| refine' Measurable.ite _ _ _ <;> norm_num; | |
| fun_prop; | |
| · exact Continuous.aestronglyMeasurable ( hf_cont.comp ( continuous_const.sub continuous_id' ) ); | |
| · filter_upwards [ ] using fun n => Filter.Eventually.of_forall fun a => by simpa [ abs_mul ] using mul_le_mul_of_nonneg_left ( hf_bdd.choose_spec ( n - a ) ) ( abs_nonneg _ ) ; | |
| · refine' MeasureTheory.Integrable.mul_const _ _; | |
| refine' MeasureTheory.Integrable.abs _; | |
| -- The second derivative of the heat kernel is integrable because it is a product of a Gaussian function and a polynomial function, both of which are integrable. | |
| have h_integrable : Integrable (fun x => Real.exp (-x^2 / (4 * t)) * (x^2 / (4 * t^2) - 1 / (2 * t))) volume := by | |
| have h_integrable : Integrable (fun x => Real.exp (-x^2 / (4 * t)) * x^2) volume := by | |
| have := @integrable_rpow_mul_exp_neg_mul_sq; | |
| convert @this ( 1 / ( 4 * t ) ) ( by positivity ) 2 ( by norm_num ) using 1 ; norm_num ; ring; | |
| ac_rfl; | |
| convert h_integrable.div_const ( 4 * t ^ 2 ) |> fun h => h.sub ( MeasureTheory.Integrable.const_mul ( show MeasureTheory.Integrable ( fun x => Real.exp ( -x ^ 2 / ( 4 * t ) ) ) volume from by simpa [ div_eq_inv_mul ] using ( integrable_exp_neg_mul_sq ( by positivity ) ) ) ( 1 / ( 2 * t ) ) ) using 2 ; ring; | |
| norm_num ; ring; | |
| convert h_integrable.const_mul ( ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ ) using 2 ; unfold heatKernel_dxx ; ring; | |
| grind; | |
| · exact Filter.Eventually.of_forall fun y => Filter.Tendsto.mul tendsto_const_nhds ( hf_cont.continuousAt.tendsto.comp ( Filter.tendsto_id.sub tendsto_const_nhds ) ); | |
| convert h_cont using 1; | |
| ext x; | |
| rw [ ← MeasureTheory.integral_sub_left_eq_self ]; | |
| swap; | |
| exacts [ x, by congr; ext y; ring ]; | |
| -- By the properties of the heat kernel, we know that $\int_{-\infty}^{\infty} \text{heatKernel}_{xx}(t, x-y) f(y) \, dy$ is continuous in $x$, and thus the limit can be passed inside the integral. | |
| have h_limit : Filter.Tendsto (fun h => ∫ u in (0 : ℝ)..1, ∫ y, heatKernel_dxx t (x + u * h - y) * f y) (nhdsWithin 0 {0}ᶜ) (nhds (∫ u in (0 : ℝ)..1, ∫ y, heatKernel_dxx t (x - y) * f y)) := by | |
| refine' tendsto_nhdsWithin_of_tendsto_nhds _; | |
| refine' intervalIntegral.tendsto_integral_filter_of_dominated_convergence _ _ _ _ _; | |
| use fun u => SupSet.sSup ( Set.image ( fun x => |∫ y, heatKernel_dxx t ( x - y ) * f y| ) ( Set.Icc ( x - 1 ) ( x + 1 ) ) ); | |
| · exact Filter.Eventually.of_forall fun n => Continuous.aestronglyMeasurable ( by exact h_cont.comp ( by continuity ) ); | |
| · rw [ Metric.eventually_nhds_iff ]; | |
| refine' ⟨ 1, by norm_num, fun y hy => Filter.Eventually.of_forall fun z hz => _ ⟩; | |
| refine' le_csSup _ _; | |
| · exact IsCompact.bddAbove ( isCompact_Icc.image ( h_cont.abs ) ); | |
| · exact ⟨ x + z * y, ⟨ by cases Set.mem_uIoc.mp hz <;> nlinarith [ abs_lt.mp hy ], by cases Set.mem_uIoc.mp hz <;> nlinarith [ abs_lt.mp hy ] ⟩, rfl ⟩; | |
| · norm_num; | |
| · exact Filter.Eventually.of_forall fun u hu => by simpa using h_cont.continuousAt.tendsto.comp ( Continuous.tendsto' ( by continuity ) _ _ <| by norm_num ) ; | |
| have h_limit : Filter.Tendsto (fun h => ∫ y, (∫ u in (0 : ℝ)..1, heatKernel_dxx t (x + u * h - y) * f y)) (nhdsWithin 0 {0}ᶜ) (nhds (∫ y, heatKernel_dxx t (x - y) * f y)) := by | |
| exact Filter.Tendsto.congr' ( Filter.eventuallyEq_of_mem self_mem_nhdsWithin fun h hh => by rw [ h_fubini h hh ] ) ( h_limit.trans ( by norm_num ) ); | |
| refine' h_limit.congr' _; | |
| filter_upwards [ self_mem_nhdsWithin ] with h hh; | |
| rw [ ← MeasureTheory.integral_sub ]; | |
| · rw [ ← MeasureTheory.integral_smul ]; | |
| refine' MeasureTheory.integral_congr_ae _; | |
| filter_upwards [ ] with y; | |
| rw [ intervalIntegral.integral_eq_sub_of_hasDerivAt ]; | |
| rotate_right; | |
| use fun u => h⁻¹ * ( heatKernel_dx t ( x + u * h - y ) * f y ); | |
| · norm_num ; ring; | |
| · intro u hu; convert HasDerivAt.const_mul ( h⁻¹ ) ( HasDerivAt.mul ( HasDerivAt.comp u ( heatKernel_hasDerivAt_xx ht _ ) ( HasDerivAt.sub ( HasDerivAt.add ( hasDerivAt_const _ _ ) ( hasDerivAt_mul_const _ ) ) ( hasDerivAt_const _ _ ) ) ) ( hasDerivAt_const _ _ ) ) using 1 ; ring; | |
| simp +decide [ mul_assoc, mul_comm h, hh ] ; ring; | |
| exact eq_div_of_mul_eq ( by aesop ) ( by ring ); | |
| · apply_rules [ Continuous.intervalIntegrable ]; | |
| refine' Continuous.mul _ continuous_const; | |
| refine' Continuous.if _ _ _; | |
| · grind +suggestions; | |
| · exact continuous_const; | |
| · fun_prop; | |
| · have h_integrable : Integrable (fun y => heatKernel_dx t y * f (x + h - y)) volume := by | |
| have h_integrable : Integrable (fun y => heatKernel_dx t y) volume := by | |
| have h_integrable : Integrable (fun y => (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-(y ^ 2 / (4 * t))) * (-(y / (2 * t)))) volume := by | |
| have h_integrable : Integrable (fun y => y * Real.exp (-(y ^ 2 / (4 * t)))) volume := by | |
| have := @integrable_rpow_mul_exp_neg_mul_sq; | |
| convert @this ( 1 / ( 4 * t ) ) ( by positivity ) 1 ( by norm_num ) using 3 ; norm_num ; ring; | |
| convert h_integrable.const_mul ( - ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ / ( 2 * t ) ) using 2 ; ring; | |
| convert h_integrable using 1; | |
| ext y; simp [heatKernel_dx, heatKernel]; | |
| grind +splitImp; | |
| refine' h_integrable.norm.mul_const _ |> fun h => h.mono' _ _; | |
| exact hf_bdd.choose; | |
| · exact h_integrable.1.mul ( hf_cont.comp ( continuous_const.sub continuous_id' ) |> Continuous.aestronglyMeasurable ); | |
| · filter_upwards [ ] using fun y => by rw [ norm_mul ] ; exact mul_le_mul_of_nonneg_left ( hf_bdd.choose_spec _ ) ( norm_nonneg _ ) ; | |
| convert h_integrable.comp_sub_left ( x + h ) using 1 ; ext ; simp +decide [ mul_comm ]; | |
| · have h_integrable : Integrable (fun y => heatKernel_dx t (x - y)) volume := by | |
| have h_integrable : Integrable (fun y => heatKernel_dx t y) volume := by | |
| have h_integrable : Integrable (fun y => (Real.sqrt (4 * Real.pi * t))⁻¹ * Real.exp (-(y ^ 2 / (4 * t))) * (-(y / (2 * t)))) volume := by | |
| have h_integrable : Integrable (fun y => y * Real.exp (-(y ^ 2 / (4 * t)))) volume := by | |
| have := @integrable_rpow_mul_exp_neg_mul_sq; | |
| convert @this ( 1 / ( 4 * t ) ) ( by positivity ) 1 ( by norm_num ) using 3 ; norm_num ; ring; | |
| convert h_integrable.const_mul ( - ( Real.sqrt ( 4 * Real.pi * t ) ) ⁻¹ / ( 2 * t ) ) using 2 ; ring; | |
| convert h_integrable using 1; | |
| ext y; simp [heatKernel_dx, heatKernel]; | |
| grind +splitImp; | |
| exact h_integrable.comp_sub_left x; | |
| refine' h_integrable.norm.mul_const _ |> fun h => h.mono' _ _; | |
| exact hf_bdd.choose; | |
| · exact h_integrable.1.mul ( hf_cont.aestronglyMeasurable ); | |
| · filter_upwards [ ] using fun y => by rw [ norm_mul ] ; exact mul_le_mul_of_nonneg_left ( hf_bdd.choose_spec y ) ( norm_nonneg _ ) ; | |
| /- | |
| The time derivative of the heat kernel equals the second spatial derivative. | |
| -/ | |
| lemma heatKernel_pde {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| HasDerivAt (fun s => heatKernel s x) (heatKernel_dxx t x) t := by | |
| convert HasDerivAt.congr_of_eventuallyEq _ ?_ using 1; | |
| exact fun s => ( Real.sqrt ( 4 * Real.pi * s ) ) ⁻¹ * Real.exp ( - ( x ^ 2 / ( 4 * s ) ) ); | |
| · convert HasDerivAt.mul ( HasDerivAt.inv ( HasDerivAt.sqrt ( HasDerivAt.const_mul ( 4 * Real.pi ) ( hasDerivAt_id' t ) ) ( by positivity ) ) ( by positivity ) ) ( HasDerivAt.exp ( HasDerivAt.neg ( HasDerivAt.div ( hasDerivAt_const _ _ ) ( HasDerivAt.const_mul 4 ( hasDerivAt_id' t ) ) ( by positivity ) ) ) ) using 1 ; norm_num [ ht.ne', Real.pi_pos.ne', heatKernel_dxx ] ; ring; | |
| grind; | |
| · filter_upwards [ lt_mem_nhds ht ] with s hs using heatKernel_of_pos hs x | |
| /- | |
| The time derivative of heatSolution: differentiate under the integral. | |
| -/ | |
| set_option maxHeartbeats 800000 in | |
| lemma heatSolution_hasDerivAt_t (f : ℝ → ℝ) (hf_cont : Continuous f) | |
| (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) {t : ℝ} (ht : 0 < t) (x : ℝ) : | |
| HasDerivAt (fun s => heatSolution f s x) | |
| (∫ y, heatKernel_dxx t (x - y) * f y) t := by | |
| obtain ⟨ M, hM ⟩ := hf_bdd; | |
| -- Apply the dominated convergence theorem to interchange the derivative and the integral. | |
| have h_dominated : Filter.Tendsto (fun h => ∫ y, (heatKernel (t + h) (x - y) - heatKernel t (x - y)) / h * f y) (nhdsWithin 0 {0}ᶜ) (nhds (∫ y, heatKernel_dxx t (x - y) * f y)) := by | |
| -- To apply the dominated convergence theorem, we need to show that the integrand is dominated by an integrable function. | |
| have h_dominate : ∀ h, abs h < t / 2 → ∀ y, abs ((heatKernel (t + h) (x - y) - heatKernel t (x - y)) / h * f y) ≤ M * (Real.sqrt (4 * Real.pi * (t / 2)))⁻¹ * Real.exp (-(x - y) ^ 2 / (8 * t)) * (1 / (t / 2) + (x - y) ^ 2 / (t / 2) ^ 2) := by | |
| -- By the properties of the heat kernel, we know that its derivative is bounded. | |
| have h_deriv_bound : ∀ h, abs h < t / 2 → ∀ y, abs (deriv (fun s => heatKernel s (x - y)) (t + h)) ≤ (Real.sqrt (4 * Real.pi * (t / 2)))⁻¹ * Real.exp (-(x - y) ^ 2 / (8 * t)) * (1 / (t / 2) + (x - y) ^ 2 / (t / 2) ^ 2) := by | |
| intros h hh y | |
| have h_deriv_bound : deriv (fun s => heatKernel s (x - y)) (t + h) = heatKernel_dxx (t + h) (x - y) := by | |
| exact HasDerivAt.deriv ( heatKernel_pde ( by linarith [ abs_lt.mp hh ] ) _ ); | |
| rw [ h_deriv_bound, heatKernel_dxx ]; | |
| split_ifs <;> norm_num; | |
| · exact mul_nonneg ( mul_nonneg ( inv_nonneg.2 ( Real.sqrt_nonneg _ ) ) ( Real.exp_nonneg _ ) ) ( add_nonneg ( div_nonneg zero_le_two ht.le ) ( div_nonneg ( sq_nonneg _ ) ( sq_nonneg _ ) ) ); | |
| · gcongr; | |
| · rw [ abs_of_nonneg ( Real.sqrt_nonneg _ ) ] ; exact Real.sqrt_le_sqrt <| by nlinarith [ Real.pi_pos, abs_lt.mp hh ] ; | |
| · rw [ neg_div, neg_le_neg_iff ]; | |
| rw [ div_le_div_iff₀ ] <;> nlinarith [ abs_lt.mp hh ]; | |
| · rw [ abs_le ]; | |
| field_simp; | |
| rw [ le_div_iff₀, div_le_iff₀ ] <;> try nlinarith; | |
| constructor <;> nlinarith [ sq_nonneg ( t + h - t / 2 ), sq_nonneg ( t + h + t / 2 ), abs_lt.mp hh, mul_le_mul_of_nonneg_left ( show t + h ≥ t / 2 by linarith [ abs_lt.mp hh ] ) ( sq_nonneg ( x - y ) ) ]; | |
| -- By the mean value theorem, there exists some $c$ between $t$ and $t + h$ such that | |
| have h_mean_value : ∀ h, abs h < t / 2 → ∀ y, h ≠ 0 → ∃ c ∈ Set.Icc (t - abs h) (t + abs h), (heatKernel (t + h) (x - y) - heatKernel t (x - y)) / h = deriv (fun s => heatKernel s (x - y)) c := by | |
| intro h hh y hy; cases' lt_or_gt_of_ne hy with hy hy <;> simp_all +decide [ div_eq_inv_mul ] ; | |
| · have := exists_deriv_eq_slope ( f := fun s => heatKernel s ( x - y ) ) ( show t + h < t by linarith ); | |
| contrapose! this; | |
| refine' ⟨ _, _, _ ⟩; | |
| · refine' ContinuousOn.congr _ _; | |
| use fun s => ( Real.sqrt ( 4 * Real.pi * s ) ) ⁻¹ * Real.exp ( - ( ( x - y ) ^ 2 / ( 4 * s ) ) ); | |
| · exact continuousOn_of_forall_continuousAt fun s hs => ContinuousAt.mul ( ContinuousAt.inv₀ ( Real.continuous_sqrt.continuousAt.comp <| ContinuousAt.mul continuousAt_const continuousAt_id ) <| ne_of_gt <| Real.sqrt_pos.mpr <| mul_pos ( by positivity ) <| by linarith [ hs.1, abs_lt.mp hh ] ) <| Real.continuous_exp.continuousAt.comp <| ContinuousAt.neg <| ContinuousAt.div continuousAt_const ( continuousAt_const.mul continuousAt_id ) <| by linarith [ hs.1, abs_lt.mp hh ] ; | |
| · intro s hs; simp +decide [ heatKernel, hs.1, hs.2 ] ; | |
| exact fun hs' => Real.sqrt_eq_zero_of_nonpos <| mul_nonpos_of_nonneg_of_nonpos ( by positivity ) hs'; | |
| · refine' fun s hs => DifferentiableAt.differentiableWithinAt _; | |
| refine' DifferentiableAt.congr_of_eventuallyEq _ _; | |
| use fun s => ( Real.sqrt ( 4 * Real.pi * s ) ) ⁻¹ * Real.exp ( - ( ( x - y ) ^ 2 / ( 4 * s ) ) ); | |
| · exact DifferentiableAt.mul ( DifferentiableAt.inv ( DifferentiableAt.sqrt ( differentiableAt_id.const_mul _ ) ( by nlinarith [ Real.pi_pos, hs.1, hs.2, abs_lt.mp hh ] ) ) ( ne_of_gt ( Real.sqrt_pos.mpr ( by nlinarith [ Real.pi_pos, hs.1, hs.2, abs_lt.mp hh ] ) ) ) ) ( DifferentiableAt.exp ( DifferentiableAt.neg ( DifferentiableAt.div ( differentiableAt_const _ ) ( differentiableAt_id.const_mul _ ) ( by nlinarith [ Real.pi_pos, hs.1, hs.2, abs_lt.mp hh ] ) ) ) ); | |
| · filter_upwards [ Ioo_mem_nhds hs.1 hs.2 ] with u hu using if_neg ( by linarith [ hu.1, hu.2, abs_lt.mp hh ] ); | |
| · intro c hc; specialize this c ⟨ by cases abs_cases h <;> linarith [ hc.1, hc.2 ], by cases abs_cases h <;> linarith [ hc.1, hc.2 ] ⟩ ; ring_nf at *; aesop; | |
| · have := exists_deriv_eq_slope ( f := fun s => heatKernel s ( x - y ) ) ( show t < t + h by linarith ); | |
| simp +zetaDelta at *; | |
| refine' this _ _ |> fun ⟨ c, hc₁, hc₂ ⟩ => ⟨ c, ⟨ by linarith [ abs_of_pos hy ], by linarith [ abs_of_pos hy ] ⟩, by rw [ hc₂, inv_mul_eq_div ] ⟩; | |
| · refine' ContinuousOn.congr _ _; | |
| use fun s => ( Real.sqrt ( 4 * Real.pi * s ) ) ⁻¹ * Real.exp ( - ( ( x - y ) ^ 2 / ( 4 * s ) ) ); | |
| · exact continuousOn_of_forall_continuousAt fun s hs => ContinuousAt.mul ( ContinuousAt.inv₀ ( Real.continuous_sqrt.continuousAt.comp <| ContinuousAt.mul continuousAt_const continuousAt_id ) <| ne_of_gt <| Real.sqrt_pos.mpr <| mul_pos ( by positivity ) <| by linarith [ hs.1 ] ) <| Real.continuous_exp.continuousAt.comp <| ContinuousAt.neg <| ContinuousAt.div continuousAt_const ( continuousAt_const.mul continuousAt_id ) <| by linarith [ hs.1 ] ; | |
| · intro s hs; simp +decide [ heatKernel, hs.1.trans' ht.le ] ; | |
| exact fun h => Or.inl <| by linarith [ hs.1 ] ; | |
| · refine' DifferentiableOn.congr _ _; | |
| use fun s => ( Real.sqrt ( 4 * Real.pi * s ) ) ⁻¹ * Real.exp ( - ( ( x - y ) ^ 2 / ( 4 * s ) ) ); | |
| · exact DifferentiableOn.mul ( DifferentiableOn.inv ( DifferentiableOn.sqrt ( differentiableOn_id.const_mul _ ) fun s hs => by nlinarith [ Real.pi_pos, hs.1 ] ) fun s hs => ne_of_gt <| Real.sqrt_pos.mpr <| by nlinarith [ Real.pi_pos, hs.1 ] ) ( DifferentiableOn.exp <| DifferentiableOn.neg <| DifferentiableOn.div ( differentiableOn_const _ ) ( differentiableOn_id.const_mul _ ) fun s hs => by nlinarith [ Real.pi_pos, hs.1 ] ); | |
| · exact fun s hs => if_neg ( by linarith [ hs.1 ] ); | |
| intro h hh y; by_cases hh' : h = 0 <;> simp_all +decide [ abs_mul, mul_assoc, mul_comm, mul_left_comm ] ; | |
| · exact mul_nonneg ( le_trans ( abs_nonneg _ ) ( hM x ) ) ( mul_nonneg ( by positivity ) ( by positivity ) ); | |
| · obtain ⟨ c, hc₁, hc₂ ⟩ := h_mean_value h hh y hh'; rw [ hc₂ ] ; | |
| gcongr; | |
| · exact le_trans ( abs_nonneg _ ) ( hM 0 ); | |
| · exact hM y; | |
| · convert h_deriv_bound ( c - t ) ( abs_lt.mpr ⟨ by linarith [ abs_nonneg h ], by linarith [ abs_nonneg h ] ⟩ ) y using 1 ; ring; | |
| -- The dominating function is integrable. | |
| have h_integrable : MeasureTheory.Integrable (fun y => M * (Real.sqrt (4 * Real.pi * (t / 2)))⁻¹ * Real.exp (-(x - y) ^ 2 / (8 * t)) * (1 / (t / 2) + (x - y) ^ 2 / (t / 2) ^ 2)) MeasureTheory.volume := by | |
| have h_integrable : MeasureTheory.Integrable (fun y => Real.exp (-(x - y) ^ 2 / (8 * t)) * (1 / (t / 2) + (x - y) ^ 2 / (t / 2) ^ 2)) MeasureTheory.volume := by | |
| have h_integrable : MeasureTheory.Integrable (fun y => Real.exp (-y ^ 2 / (8 * t)) * (1 / (t / 2) + y ^ 2 / (t / 2) ^ 2)) MeasureTheory.volume := by | |
| have h_integrable : MeasureTheory.Integrable (fun y => Real.exp (-y ^ 2 / (8 * t)) * y ^ 2) MeasureTheory.volume := by | |
| have := @integrable_rpow_mul_exp_neg_mul_sq; | |
| convert @this ( 1 / ( 8 * t ) ) ( by positivity ) 2 ( by norm_num ) using 1 ; norm_num ; ring; | |
| ac_rfl; | |
| convert h_integrable.div_const ( t ^ 2 / 4 ) |> MeasureTheory.Integrable.add <| MeasureTheory.Integrable.const_mul ( show MeasureTheory.Integrable ( fun y => Real.exp ( -y ^ 2 / ( 8 * t ) ) ) volume from ?_ ) ( 2 / t ) using 2 ; ring; | |
| · norm_num ; ring; | |
| · simpa [ div_eq_inv_mul ] using ( integrable_exp_neg_mul_sq ( by positivity ) ); | |
| convert h_integrable.comp_sub_left x using 1; | |
| convert h_integrable.const_mul ( M * ( Real.sqrt ( 4 * Real.pi * ( t / 2 ) ) ) ⁻¹ ) using 2 ; ring; | |
| refine' MeasureTheory.tendsto_integral_filter_of_dominated_convergence _ _ _ _ _; | |
| use fun y => M * ( Real.sqrt ( 4 * Real.pi * ( t / 2 ) ) ) ⁻¹ * Real.exp ( - ( x - y ) ^ 2 / ( 8 * t ) ) * ( 1 / ( t / 2 ) + ( x - y ) ^ 2 / ( t / 2 ) ^ 2 ); | |
| · refine' Filter.eventually_of_mem self_mem_nhdsWithin fun n hn => Measurable.aestronglyMeasurable _; | |
| unfold heatKernel; | |
| split_ifs <;> fun_prop; | |
| · filter_upwards [ self_mem_nhdsWithin, mem_nhdsWithin_of_mem_nhds ( Metric.ball_mem_nhds _ <| half_pos ht ) ] with n hn hn' using Filter.Eventually.of_forall fun y => h_dominate n ( by simpa using hn' ) y; | |
| · exact h_integrable; | |
| · refine' Filter.Eventually.of_forall fun y => _; | |
| have h_deriv : HasDerivAt (fun s => heatKernel s (x - y)) (heatKernel_dxx t (x - y)) t := by | |
| exact?; | |
| simpa [ div_eq_inv_mul ] using h_deriv.tendsto_slope_zero.mul_const ( f y ); | |
| rw [ hasDerivAt_iff_tendsto_slope_zero ]; | |
| refine' h_dominated.congr' _; | |
| filter_upwards [ self_mem_nhdsWithin, mem_nhdsWithin_of_mem_nhds ( Metric.ball_mem_nhds _ ht ) ] with h hh hh' ; simp_all +decide [ div_eq_inv_mul, MeasureTheory.integral_const_mul, MeasureTheory.integral_sub, heatSolution ]; | |
| rw [ ← MeasureTheory.integral_sub ]; | |
| · rw [ ← MeasureTheory.integral_const_mul ] ; congr ; ext ; ring; | |
| · refine' MeasureTheory.Integrable.mono' _ _ _; | |
| refine' fun y => M * heatKernel ( t + h ) ( x - y ); | |
| · refine' MeasureTheory.Integrable.const_mul _ _; | |
| exact MeasureTheory.Integrable.comp_sub_left ( heatKernel_integrable ( show 0 < t + h by linarith [ abs_lt.mp hh' ] ) ) x; | |
| · exact Continuous.aestronglyMeasurable ( by unfold heatKernel; split_ifs <;> continuity ); | |
| · filter_upwards [ ] with y using by rw [ Real.norm_eq_abs, abs_mul, abs_of_nonneg ( show 0 ≤ heatKernel ( t + h ) ( x - y ) from by unfold heatKernel; split_ifs <;> positivity ) ] ; nlinarith [ hM y, show 0 ≤ heatKernel ( t + h ) ( x - y ) from by unfold heatKernel; split_ifs <;> positivity ] ; | |
| · apply_rules [ heatSolution_integrable ]; | |
| use M | |
| -- ============================================================================ | |
| -- Main theorem | |
| -- ============================================================================ | |
| theorem heat_kernel_solves_heat_equation (f : ℝ → ℝ) (hf_cont : Continuous f) (hf_bdd : ∃ M : ℝ, ∀ x, |f x| ≤ M) : | |
| -- The PDE on (0, ∞) × ℝ. | |
| (∀ t : ℝ, 0 < t → ∀ x : ℝ, ∃ ux : ℝ → ℝ, ∃ uxx : ℝ, | |
| (∀ y : ℝ, HasDerivAt (fun z => heatSolution f t z) (ux y) y) ∧ | |
| HasDerivAt ux uxx x ∧ | |
| HasDerivAt (fun s => heatSolution f s x) uxx t) ∧ | |
| -- Initial condition recovered as a one-sided limit at t = 0. | |
| (∀ x : ℝ, | |
| Filter.Tendsto (fun t : ℝ => heatSolution f t x) | |
| (nhdsWithin (0 : ℝ) (Set.Ioi 0)) (nhds (f x))) := by | |
| constructor | |
| · -- PDE part | |
| intro t ht x | |
| refine ⟨fun z => ∫ y, heatKernel_dx t (z - y) * f y, | |
| ∫ y, heatKernel_dxx t (x - y) * f y, ?_, ?_, ?_⟩ | |
| · intro y | |
| exact heatSolution_hasDerivAt_x f hf_cont hf_bdd ht y | |
| · exact heatSolution_hasDerivAt_xx f hf_cont hf_bdd ht x | |
| · exact heatSolution_hasDerivAt_t f hf_cont hf_bdd ht x | |
| · -- Initial condition | |
| exact heatSolution_initial f hf_cont hf_bdd | |
| end | |
| end Submission |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Lean | |
| open Lean | |
| def comparatorExists (comparatorBin : String) : IO Bool := do | |
| if comparatorBin.contains '/' then | |
| return (← System.FilePath.pathExists comparatorBin) | |
| try | |
| let child ← IO.Process.spawn { | |
| cmd := "sh" | |
| args := #["-c", "command -v \"$1\" >/dev/null 2>&1", "sh", comparatorBin] | |
| } | |
| let exitCode ← child.wait | |
| return exitCode == 0 | |
| catch _ => | |
| return false | |
| def main : IO UInt32 := do | |
| let comparatorBin := (← IO.getEnv "COMPARATOR_BIN").getD "comparator" | |
| if !(← comparatorExists comparatorBin) then | |
| IO.eprintln s!"Failed to run comparator via `{comparatorBin}`." | |
| IO.eprintln "Make sure `comparator` is installed and on your `PATH`, or set `COMPARATOR_BIN=/path/to/comparator`." | |
| IO.eprintln "See the root repository README for comparator setup details, including landrun and lean4export." | |
| pure 1 | |
| else | |
| try | |
| let child ← IO.Process.spawn { | |
| cmd := "lake" | |
| args := #["env", comparatorBin, "config.json"] | |
| } | |
| let exitCode ← child.wait | |
| pure exitCode | |
| catch err => | |
| IO.eprintln s!"Failed to run comparator via `{comparatorBin}`." | |
| IO.eprintln "Make sure `comparator` is installed and on your `PATH`, or set `COMPARATOR_BIN=/path/to/comparator`." | |
| IO.eprintln "See the root repository README for comparator setup details, including landrun and lean4export." | |
| IO.eprintln s!"Original error: {err}" | |
| pure 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment