From a0e1d681ab855174d16ba731446912de5baae23b Mon Sep 17 00:00:00 2001 From: ichxorya Date: Mon, 23 Feb 2026 00:54:32 +0700 Subject: [PATCH 01/12] feat(thermodynamics): initialize large scale changes and updates in the Thermodynamics module (with some extend to StatisticalMechanics since it depends on Thermodynamics) --- .../BoltzmannConstant.lean | 8 +- .../CanonicalEnsemble/Basic.lean | 4 +- .../CanonicalEnsemble/Finite.lean | 49 +- .../CanonicalEnsemble/Lemmas.lean | 58 +- PhysLean/Thermodynamics/Basic.lean | 4 +- .../Thermodynamics/Temperature/Basic.lean | 1041 +++++++++++++---- .../Temperature/TemperatureScales.lean | 241 ++++ .../Temperature/TemperatureUnits.lean | 15 +- 8 files changed, 1172 insertions(+), 248 deletions(-) create mode 100644 PhysLean/Thermodynamics/Temperature/TemperatureScales.lean diff --git a/PhysLean/StatisticalMechanics/BoltzmannConstant.lean b/PhysLean/StatisticalMechanics/BoltzmannConstant.lean index 5ddf4e05a..5e642580f 100644 --- a/PhysLean/StatisticalMechanics/BoltzmannConstant.lean +++ b/PhysLean/StatisticalMechanics/BoltzmannConstant.lean @@ -1,5 +1,5 @@ /- -Copyright (c) 2025 Joseph Tooby-Smith. All rights reserved. +Copyright (c) 2026 Joseph Tooby-Smith. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Joseph Tooby-Smith -/ @@ -25,13 +25,13 @@ def kBAx : {p : ℝ | 0 < p} := ⟨1.380649e-23, by norm_num⟩ /-- The Boltzmann constant in a given but arbitrary set of units. Boltzman's constant has dimension equivalent to `Energy/Temperature`. -/ -noncomputable def kB : ℝ := kBAx.1 +noncomputable def kB : ℝ := kBAx.val /-- The Boltzmann constant is positive. -/ -lemma kB_pos : 0 < kB := kBAx.2 +lemma kB_pos : 0 < kB := kBAx.property /-- The Boltzmann constant is non-negative. -/ -lemma kB_nonneg : 0 ≤ kB := le_of_lt kBAx.2 +lemma kB_nonneg : 0 ≤ kB := le_of_lt kBAx.property /-- The Boltzmann constant is not equal to zero. -/ lemma kB_ne_zero : kB ≠ 0 := by diff --git a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean index 31bfc4909..82bd5e9ad 100644 --- a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean +++ b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean @@ -370,7 +370,7 @@ lemma μBolt_ne_zero_of_μ_ne_zero (T : Temperature) (h : 𝓒.μ ≠ 0) : simp [μBolt] at ⊢ h rw [Measure.ext_iff'] at ⊢ h simp only [Measure.coe_zero, Pi.zero_apply] - have hs : {x | ENNReal.ofReal (rexp (-(↑T.β * 𝓒.energy x))) ≠ 0} = Set.univ := by + have hs : {x | ENNReal.ofReal (rexp (-(T.toReal⁻¹ * Constants.kB⁻¹ * 𝓒.energy x))) ≠ 0} = Set.univ := by ext i simp only [ne_eq, ENNReal.ofReal_eq_zero, not_le, Set.mem_setOf_eq, Set.mem_univ, iff_true] exact exp_pos _ @@ -454,7 +454,7 @@ lemma mathematicalPartitionFunction_eq_zero_iff (T : Temperature) [IsFiniteMeasu have h : s = Set.univ := by ext i simp [s] - exact exp_pos (-(T.β * 𝓒.energy i)) + exact exp_pos (-(T.toReal⁻¹ * Constants.kB⁻¹ * 𝓒.energy i)) change 𝓒.μ s = 0 ↔ 𝓒.μ = 0 rw [h] simp only [Measure.measure_univ_eq_zero] diff --git a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Finite.lean b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Finite.lean index faeb73508..e5c586993 100644 --- a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Finite.lean +++ b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Finite.lean @@ -293,8 +293,18 @@ lemma sum_probability_eq_one have hZdef := mathematicalPartitionFunction_of_fintype (𝓒:=𝓒) T have hZpos := mathematicalPartitionFunction_pos_finite (𝓒:=𝓒) (T:=T) have hZne : 𝓒.mathematicalPartitionFunction T ≠ 0 := hZpos.ne' - simp [hZdef] - simp_all only [neg_mul, ne_eq, not_false_eq_true] + have hZdef' : 𝓒.mathematicalPartitionFunction T = + ∑ x, rexp (-(T.toReal⁻¹ * kB⁻¹ * 𝓒.energy x)) := by + simpa [Temperature.β, one_div, mul_comm, mul_left_comm, mul_assoc] using hZdef + have hZne' : ∑ x, rexp (-(T.toReal⁻¹ * kB⁻¹ * 𝓒.energy x)) ≠ 0 := by + rw [← hZdef'] + exact hZne + have hnum : + ∑ x, rexp (-↑T.β * 𝓒.energy x) = ∑ x, rexp (-(T.toReal⁻¹ * kB⁻¹ * 𝓒.energy x)) := by + simp [Temperature.β, one_div, mul_comm, mul_assoc] + rw [hZdef'] + rw [hnum] + field_simp [hZne'] /-- The entropy of a finite canonical ensemble (Shannon entropy) is non-negative. -/ lemma entropy_nonneg [MeasurableSingletonClass ι] [IsFinite 𝓒] [Nonempty ι] (T : Temperature) : @@ -409,11 +419,29 @@ lemma meanEnergy_Beta_eq_finite [MeasurableSingletonClass ι] [IsFinite 𝓒] (b 𝓒.meanEnergyBeta b = 𝓒.meanEnergyBetaReal b := by let T := Temperature.ofβ (Real.toNNReal b) have hT_beta : (T.β : ℝ) = b := by - simp [T, Real.toNNReal_of_nonneg hb.le] + change ((Temperature.ofβ (Real.toNNReal b)).β : ℝ) = b + simpa [Real.toNNReal_of_nonneg hb.le] using + congrArg (fun x : NNReal => (x : ℝ)) (Temperature.β_ofβ (Real.toNNReal b)) + have hT_beta' : T.toReal⁻¹ * kB⁻¹ = b := by + simpa [Temperature.β, one_div, mul_comm, mul_left_comm, mul_assoc] using hT_beta rw [meanEnergyBeta, meanEnergy_of_fintype 𝓒 T, meanEnergyBetaReal] refine Finset.sum_congr rfl fun i _ => ?_ - simp [CanonicalEnsemble.probability, probabilityBetaReal, - mathematicalPartitionFunction_of_fintype, mathematicalPartitionFunctionBetaReal, hT_beta] + have hden : 𝓒.mathematicalPartitionFunction T = 𝓒.mathematicalPartitionFunctionBetaReal b := by + rw [mathematicalPartitionFunction_of_fintype, mathematicalPartitionFunctionBetaReal] + refine Finset.sum_congr rfl ?_ + intro j hj + simp [hT_beta'] + have hprob : + rexp (-(T.toReal⁻¹ * kB⁻¹ * 𝓒.energy i)) / 𝓒.mathematicalPartitionFunction T + = rexp (-(b * 𝓒.energy i)) / 𝓒.mathematicalPartitionFunctionBetaReal b := by + calc + rexp (-(T.toReal⁻¹ * kB⁻¹ * 𝓒.energy i)) / 𝓒.mathematicalPartitionFunction T + = rexp (-(b * 𝓒.energy i)) / 𝓒.mathematicalPartitionFunction T := by + simp [hT_beta'] + _ = rexp (-(b * 𝓒.energy i)) / 𝓒.mathematicalPartitionFunctionBetaReal b := by + rw [hden] + simpa [CanonicalEnsemble.probability, probabilityBetaReal] using + congrArg (fun p => 𝓒.energy i * p) hprob lemma differentiable_meanEnergyBetaReal [Nonempty ι] : Differentiable ℝ 𝓒.meanEnergyBetaReal := by @@ -568,7 +596,7 @@ lemma derivWithin_meanEnergy_Beta_eq_neg_variance [MeasurableSingletonClass ι][𝓒.IsFinite] (T : Temperature) (hT_pos : 0 < T.val) : derivWithin 𝓒.meanEnergyBeta (Set.Ioi 0) (T.β : ℝ) = - 𝓒.energyVariance T := by let β₀ := (T.β : ℝ) - have hβ₀_pos : 0 < β₀ := beta_pos T hT_pos + have hβ₀_pos : 0 < β₀ := β_pos T hT_pos have h_eq_on : Set.EqOn 𝓒.meanEnergyBeta 𝓒.meanEnergyBetaReal (Set.Ioi 0) := by intro b hb; exact meanEnergy_Beta_eq_finite 𝓒 b hb rw [derivWithin_congr h_eq_on (h_eq_on hβ₀_pos)] @@ -578,8 +606,11 @@ lemma derivWithin_meanEnergy_Beta_eq_neg_variance rw [deriv_meanEnergyBetaReal 𝓒 β₀] have h_U_eq : 𝓒.meanEnergyBetaReal β₀ = 𝓒.meanEnergy T := by rw [← meanEnergy_Beta_eq_finite 𝓒 β₀ hβ₀_pos] - simp [meanEnergyBeta] - simp_all only [NNReal.coe_pos, toNNReal_coe, ofβ_β, β₀] + change 𝓒.meanEnergy (Temperature.ofβ (Real.toNNReal β₀)) = 𝓒.meanEnergy T + have hβ₀_toNNReal : Real.toNNReal β₀ = T.β := by + change Real.toNNReal ((T.β : ℝ)) = T.β + simpa using (show Real.toNNReal ((T.β : ℝ)) = T.β from Real.toNNReal_coe) + rw [hβ₀_toNNReal, Temperature.ofβ_β] have h_prob_eq (i : ι) : 𝓒.probabilityBetaReal β₀ i = 𝓒.probability T i := by unfold probabilityBetaReal CanonicalEnsemble.probability congr 1 @@ -594,7 +625,7 @@ lemma derivWithin_meanEnergy_Beta_eq_neg_variance theorem fluctuation_dissipation_theorem_finite [MeasurableSingletonClass ι] [𝓒.IsFinite] (T : Temperature) (hT_pos : 0 < T.val) : 𝓒.heatCapacity T = 𝓒.energyVariance T / (kB * (T.val : ℝ)^2) := by - have hβ₀_pos : 0 < (T.β : ℝ) := beta_pos T hT_pos + have hβ₀_pos : 0 < (T.β : ℝ) := β_pos T hT_pos let β₀ := (T.β : ℝ) have h_diff_U_beta : DifferentiableWithinAt ℝ 𝓒.meanEnergyBeta (Set.Ioi 0) β₀ := by have h_eq_on : Set.EqOn 𝓒.meanEnergyBeta 𝓒.meanEnergyBetaReal (Set.Ioi 0) := by diff --git a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean index ef1c14fcf..41691a8ab 100644 --- a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean +++ b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean @@ -266,7 +266,10 @@ theorem helmholtzFreeEnergy_eq_meanEnergy_sub_temp_mul_thermodynamicEntropy _ = _ := by simp [add_comm, sub_eq_add_neg, mul_comm, mul_left_comm, mul_assoc] have hkβT : T.val * (kB * (T.β : ℝ)) = 1 := by - simp [hkβ, hTne] + rw [hkβ] + field_simp [hTne] + have hkβT' : T.val * (kB * (kB⁻¹ * T.toReal⁻¹)) = 1 := by + simpa [Temperature.β, one_div, mul_comm, mul_left_comm, mul_assoc] using hkβT have h_rhs : 𝓒.meanEnergy T - T.val * 𝓒.thermodynamicEntropy T = -kB * T.val * @@ -289,7 +292,7 @@ theorem helmholtzFreeEnergy_eq_meanEnergy_sub_temp_mul_thermodynamicEntropy _ = 𝓒.meanEnergy T - 1 * 𝓒.meanEnergy T - T.val * kB * Real.log (𝓒.mathematicalPartitionFunction T) + T.val * kB * 𝓒.dof * Real.log 𝓒.phaseSpaceunit := by - simp [hkβT, mul_comm, mul_assoc] + simp [hkβT', mul_comm, mul_assoc] _ = -kB * T.val * (Real.log (𝓒.mathematicalPartitionFunction T) - (𝓒.dof : ℝ) * Real.log 𝓒.phaseSpaceunit) := by @@ -518,12 +521,11 @@ lemma meanEnergy_eq_neg_deriv_log_mathZ_of_beta (fun β : ℝ => Real.log (∫ i, Real.exp (-β * 𝓒.energy i) ∂𝓒.μ)) (Set.Ioi 0) (T.β : ℝ)) := by set f : ℝ → ℝ := fun β => ∫ i, Real.exp (-β * 𝓒.energy i) ∂𝓒.μ - have hβ_pos : 0 < (T.β : ℝ) := beta_pos T hT_pos + have hβ_pos : 0 < (T.β : ℝ) := β_pos T hT_pos have hZpos : 0 < f (T.β : ℝ) := by have hZ := mathematicalPartitionFunction_pos (𝓒:=𝓒) (T:=T) - have hEq : f (T.β : ℝ) = 𝓒.mathematicalPartitionFunction T := by - simp [f, mathematicalPartitionFunction_eq_integral (𝓒:=𝓒) (T:=T)] - simpa [hEq] using hZ + simpa [f, mathematicalPartitionFunction_eq_integral (𝓒:=𝓒) (T:=T), + Temperature.β, one_div, mul_comm, mul_left_comm, mul_assoc] using hZ have h_log : HasDerivWithinAt (fun β : ℝ => Real.log (f β)) @@ -548,14 +550,12 @@ lemma meanEnergy_eq_neg_deriv_log_mathZ_of_beta = (1 / f (T.β : ℝ)) * (- ∫ i, 𝓒.energy i * Real.exp (-(T.β : ℝ) * 𝓒.energy i) ∂𝓒.μ) := h_log.derivWithin hUD - have h_f_eval : - f (T.β : ℝ) = ∫ i, Real.exp (-(T.β : ℝ) * 𝓒.energy i) ∂𝓒.μ := rfl have h_ratio : (∫ i, 𝓒.energy i * Real.exp (-(T.β : ℝ) * 𝓒.energy i) ∂𝓒.μ) / (∫ i, Real.exp (-(T.β : ℝ) * 𝓒.energy i) ∂𝓒.μ) = (1 / f (T.β : ℝ)) * (∫ i, 𝓒.energy i * Real.exp (-(T.β : ℝ) * 𝓒.energy i) ∂𝓒.μ) := by - simp [h_f_eval, div_eq_mul_inv, mul_comm] + simp [f, div_eq_mul_inv, mul_comm, mul_left_comm, mul_assoc] calc 𝓒.meanEnergy T = _ := h_mean_ratio _ = (1 / f (T.β : ℝ)) * @@ -611,16 +611,29 @@ lemma log_phys_eq_log_math_sub_const_on_Ioi Real.log (𝓒.partitionFunction (Temperature.ofβ (Real.toNNReal β))) = -((𝓒.dof : ℝ) * Real.log 𝓒.phaseSpaceunit) + Real.log (∫ i, Real.exp (-β * 𝓒.energy i) ∂ 𝓒.μ) := by - have h_integral_pos : 0 < ∫ i, Real.exp (-β * 𝓒.energy i) ∂ 𝓒.μ := by - have h_eq : ∫ i, Real.exp (-β * 𝓒.energy i) ∂ 𝓒.μ = - ∫ i, Real.exp (-(Real.toNNReal β).val * 𝓒.energy i) ∂ 𝓒.μ := by - simp [hβnn] - rw [h_eq] - simp [mathematicalPartitionFunction_eq_integral - (𝓒:=𝓒) (T:=Temperature.ofβ (Real.toNNReal β))] at hZpos - simp [hZpos] have h_beta_eq : (Temperature.ofβ (Real.toNNReal β)).β = Real.toNNReal β := by - simp_all only [gt_iff_lt, mem_Ioi, coe_toNNReal', sup_eq_left, log_pow, neg_mul, β_ofβ] + simp_all only [gt_iff_lt, mem_Ioi, coe_toNNReal', sup_eq_left, log_pow, β_ofβ] + have h_integral_pos : 0 < ∫ i, Real.exp (-β * 𝓒.energy i) ∂ 𝓒.μ := by + have h_int_eq0 : + ∫ i, Real.exp (-((Temperature.ofβ (Real.toNNReal β)).β : ℝ) * 𝓒.energy i) ∂ 𝓒.μ = + 𝓒.mathematicalPartitionFunction (Temperature.ofβ (Real.toNNReal β)) := by + exact (mathematicalPartitionFunction_eq_integral + (𝓒:=𝓒) (T:=Temperature.ofβ (Real.toNNReal β))).symm + have h_int_eq : ∫ i, Real.exp (-β * 𝓒.energy i) ∂ 𝓒.μ = + 𝓒.mathematicalPartitionFunction (Temperature.ofβ (Real.toNNReal β)) := by + have h_int_eq1 : + ∫ i, Real.exp (-(β * (kB * (kB⁻¹ * 𝓒.energy i)))) ∂ 𝓒.μ = + 𝓒.mathematicalPartitionFunction (Temperature.ofβ (Real.toNNReal β)) := by + simpa [Temperature.β, hβnn, one_div, mul_comm, mul_left_comm, mul_assoc] using h_int_eq0 + have h_int_eq2 : + ∫ i, Real.exp (-(β * (kB * (kB⁻¹ * 𝓒.energy i)))) ∂ 𝓒.μ = + ∫ i, Real.exp (-β * 𝓒.energy i) ∂ 𝓒.μ := by + refine integral_congr_ae ?_ + filter_upwards with i + field_simp [kB_ne_zero] + exact h_int_eq2.symm.trans h_int_eq1 + rw [h_int_eq] + exact hZpos rw [partitionFunction_def, mathematicalPartitionFunction_eq_integral (𝓒:=𝓒) (T:=Temperature.ofβ (Real.toNNReal β)), h_beta_eq, @@ -663,7 +676,7 @@ lemma derivWithin_log_phys_eq_derivWithin_log_math have h_eq' : Set.EqOn F_phys (fun β => F_math β - C) (Set.Ioi (0:ℝ)) := by simpa [F_phys, F_math] using h_eq - have h_mem : (T.β : ℝ) ∈ Set.Ioi (0:ℝ) := beta_pos T hT_pos + have h_mem : (T.β : ℝ) ∈ Set.Ioi (0:ℝ) := β_pos T hT_pos have h_congr : derivWithin F_phys (Set.Ioi 0) (T.β : ℝ) = derivWithin (fun β => F_math β - C) (Set.Ioi 0) (T.β : ℝ) := by @@ -769,12 +782,11 @@ lemma heatCapacity_eq_deriv_meanEnergyBeta = (derivWithin (𝓒.meanEnergyBeta) (Set.Ioi 0) (T.β : ℝ)) * (-1 / (kB * (T.val : ℝ)^2)) := by unfold heatCapacity meanEnergy_T - have h_U_eq_comp : (𝓒.meanEnergy_T) = fun t : ℝ => (𝓒.meanEnergyBeta) (betaFromReal t) := by + have h_U_eq_comp : (𝓒.meanEnergy_T) = fun t : ℝ => (𝓒.meanEnergyBeta) (βFromReal t) := by funext t - dsimp [meanEnergy_T, meanEnergyBeta, betaFromReal] - simp + simp only [meanEnergy_T, meanEnergyBeta, βFromReal, Real.toNNReal_coe, Temperature.ofβ_β] let dUdβ := derivWithin (𝓒.meanEnergyBeta) (Set.Ioi 0) (T.β : ℝ) - have h_chain := chain_rule_T_beta (F:=𝓒.meanEnergyBeta) (F':=dUdβ) T hT_pos hU_deriv + have h_chain := chain_rule_T_β (F:=𝓒.meanEnergyBeta) (F':=dUdβ) T hT_pos hU_deriv have h_UD : UniqueDiffWithinAt ℝ (Set.Ioi (0 : ℝ)) (T.val : ℝ) := (isOpen_Ioi : IsOpen (Set.Ioi (0 : ℝ))).uniqueDiffWithinAt hT_pos diff --git a/PhysLean/Thermodynamics/Basic.lean b/PhysLean/Thermodynamics/Basic.lean index f58a0b4de..2f7e82d23 100644 --- a/PhysLean/Thermodynamics/Basic.lean +++ b/PhysLean/Thermodynamics/Basic.lean @@ -1,7 +1,7 @@ /- -Copyright (c) 2025 Joseph Tooby-Smith. All rights reserved. +Copyright (c) 2026 Joseph Tooby-Smith. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Joseph Tooby-Smith +Authors: Trong-Nghia Be, Tan-Phuoc-Hung Le, Joseph Tooby-Smith -/ /-! diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index ef6109dea..d7c5b7120 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -1,271 +1,913 @@ /- -Copyright (c) 2025 Joseph Tooby-Smith. All rights reserved. +Copyright (c) 2026 Joseph Tooby-Smith. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Matteo Cipollina, Joseph Tooby-Smith +Authors: Trong-Nghia Be, Matteo Cipollina, Tan-Phuoc-Hung Le, Joseph Tooby-Smith -/ import Mathlib.Analysis.Calculus.Deriv.Inv import Mathlib.Analysis.InnerProductSpace.Basic import PhysLean.StatisticalMechanics.BoltzmannConstant import PhysLean.Meta.TODO.Basic -/-! +/-! # Temperature -In this module we define the type `Temperature`, corresponding to the temperature in a given -(but arbitrary) set of units which have absolute zero at zero. - -This is the version of temperature most often used in undergraduate and -non-mathematical physics. +In this module we define the type `Temperature`, corresponding to absolute thermodynamic temperature measured in kelvin. -The choice of units can be made on a case-by-case basis, as long as they are done consistently. +This is the version of temperature most often used in undergraduate and non-mathematical physics. +For affine display scales with offsets (such as Celsius and Fahrenheit), see +`PhysLean.Thermodynamics.Temperature.TemperatureScales`. -/ open NNReal -/-- The type `Temperature` represents the temperature in a given (but arbitrary) set of units - (preserving zero). It currently wraps `ℝ≥0`, i.e., absolute temperature in nonnegative reals. -/ +/-- The type `Temperature` represents absolute thermodynamic temperature in kelvin. + - `val` of type `ℝ≥0`: The nonnegative real value of the temperature. +-/ structure Temperature where /-- The nonnegative real value of the temperature. -/ val : ℝ≥0 +/-! +## Basic instances and definitions for `Temperature`. + +In this namespace we provide basic instances and definitions for the `Temperature` type, including +coercions to `ℝ≥0` and `ℝ`, the definition of inverse temperature `β`, and basic lemmas about these +concepts. +-/ namespace Temperature open Constants -/-- Coercion to `ℝ≥0`. -/ -instance : Coe Temperature ℝ≥0 := ⟨fun T => T.val⟩ +/-- Type coercion (implicit casting) from `Temperature` to `ℝ≥0`. + +Defined as a function that takes a `Temperature` and returns its underlying `ℝ≥0` value (by +accessing the `val` field). +-/ +instance : Coe Temperature ℝ≥0 := ⟨fun (T : Temperature) => T.val⟩ -/-- The underlying real-number associated with the temperature. -/ +/-- Convert a `Temperature` to a real number. +-/ noncomputable def toReal (T : Temperature) : ℝ := NNReal.toReal T.val -/-- Coercion to `ℝ`. -/ -noncomputable instance : Coe Temperature ℝ := ⟨toReal⟩ +/-- Type coercion (implicit casting) from `Temperature` to `ℝ`. + +Defined as a function that takes a `Temperature` and returns the `val` field converted to `ℝ`. +-/ +noncomputable instance : Coe Temperature ℝ := ⟨fun (T : Temperature) => Temperature.toReal T⟩ + +/-- Topology on `Temperature` induced from `ℝ≥0`. -/-- Topology on `Temperature` induced from `ℝ≥0`. -/ -instance : TopologicalSpace Temperature := - TopologicalSpace.induced (fun T : Temperature => (T.val : ℝ≥0)) inferInstance +Defined using the `induced` topology from the coercion function that maps a `Temperature` to its +real number representation in `ℝ≥0`. +-/ +instance : TopologicalSpace Temperature := TopologicalSpace.induced + (fun (T : Temperature) => (T : ℝ≥0)) inferInstance +/-- The zero temperature (absolute zero) in kelvin. -/ instance : Zero Temperature := ⟨⟨0⟩⟩ -@[ext] lemma ext {T₁ T₂ : Temperature} (h : T₁.val = T₂.val) : T₁ = T₂ := by - cases T₁; cases T₂; cases h; rfl +/-- Extensionality lemma for `Temperature`. + +Two `Temperature` instances are equal if their underlying `val` fields are equal. +-/ +@[ext] +lemma ext {T₁ T₂ : Temperature} (h_eq : T₁.val = T₂.val) : T₁ = T₂ := by + -- Substitutes `T₁` with its constructor form. We have `T₁ = ⟨val := T₁val⟩` in `h_eq` and the + -- goal. + cases T₁ with + | mk T₁val + -- Substitutes `T₂` with its constructor form. We have `T₂ = ⟨val := T₂val⟩` in `h_eq` and the + -- goal. + cases T₂ with + | mk T₂val + -- The proof currently has `h_eq: { val := T₁val }.val = { val := T₂val }.val` and + -- `⊢ ⟨val := T₁val⟩.val = ⟨val := T₂val⟩.val`. + -- Substitutes `h_eq` into the goal, replacing `T₂.val` with `T₁.val`. We now have + -- `⊢ ⟨val := T₁val⟩.val = ⟨val := T₁val⟩.val`. + cases h_eq + -- As the LHS and RHS are identical, this is true by reflexivity of equality (`rfl`). QED. + rfl + +/-- Simplification lemma for `Temperature`: + +Zero is less than or equal to the real number representation of a `Temperature` in `ℝ≥0`. +-/ +@[simp] +lemma zero_le_nnreal (T : Temperature) : 0 ≤ (T : ℝ≥0) := by + -- Since `T : ℝ≥0` is defined as `T.val`, we can directly use the fact that `T.val` has the type + -- `ℝ≥0`, which carries the proof of its non-negativity as part of its type. + -- Therefore, we can conclude that `0 ≤ (T : ℝ≥0)` by using the property of `T.val`. QED. + exact T.val.property + +/-- Simplification lemma for `Temperature`: + +The real number representation of a `Temperature` is greater or equal to zero in `ℝ≥0`. +-/ +@[simp] +lemma nnreal_ge_zero (T : Temperature) : (T : ℝ≥0) ≥ 0 := by + -- This is a direct consequence of `zero_le_nnreal T` and the equivalence between `a ≤ b` and + -- `b ≥ a`. QED. + exact zero_le_nnreal T + +/-- Simplification lemma for `Temperature`: + +Zero is less than or equal to the real number representation of a `Temperature` in `ℝ`. +-/ +@[simp] +lemma zero_le_real (T : Temperature) : 0 ≤ (T : ℝ) := by + -- Since `T : ℝ` is defined as `Temperature.toReal T`, which is `NNReal.toReal T.val`, we can use + -- the fact that `T.val` of type `ℝ≥0` is non-negative (previously established in + -- `zero_le_nnreal T`). + -- We also know that the function `NNReal.toReal` preserves the order of non-negativity, meaning + -- that if `0 ≤ (T : ℝ≥0)`, then `0 ≤ (T : ℝ)` as well. QED. + exact zero_le_nnreal T + +/-- Simplification lemma for `Temperature`: + +The real number representation of a `Temperature` is greater or equal to zero. +-/ +@[simp] +lemma real_ge_zero (T : Temperature) : (T : ℝ) ≥ 0 := by + -- This is a direct consequence of `zero_le_real T` and the equivalence between `a ≤ b` and + -- `b ≥ a`. QED. + exact zero_le_real T + +/-- Calculate the inverse temperature `β` corresponding to a given temperature `T`. + +- Note: + +1. This has dimensions equivalent to `Energy` to the power `-1`. Refer to the concept of +"thermodynamic beta" in thermodynamics for more details. -/-- The inverse temperature defined as `1/(kB * T)` in a given, but arbitrary set of units. - This has dimensions equivalent to `Energy`. -/ +2. Currently this formula allows for "non-negative" temperatures, which includes absolute zero in +the denominator. In physical terms, absolute zero is a limit that cannot be reached, and the formula +for `β` is not well-defined at `T = 0`. Therefore, while the type `Temperature` allows for `T = 0`, +we should refactor this definition in the future to exclude absolute zero, either by refining the +domain or by defining `β` as a partial function that is only defined for strictly positive +temperatures. +-/ noncomputable def β (T : Temperature) : ℝ≥0 := + -- Given the formula `(1 / (kB * (T : ℝ))) : ℝ≥0`, we need to show that this is non-negative to + -- fit the type `ℝ≥0`. ⟨1 / (kB * (T : ℝ)), by + -- To show that `1 / (kB * (T : ℝ))` is non-negative, we apply `div_nonneg`, which requires us + -- to show that the numerator is non-negative and the denominator is non-negative [See Note 2]. apply div_nonneg + -- `case ha`: The goal is `⊢ 0 ≤ 1`, which is true by `zero_le_one`, since `1` is a non-negative + -- real number. QED for this case. · exact zero_le_one + -- `case hb`: The goal is `⊢ 0 ≤ kB * (T : ℝ)`, which we can show by applying `mul_nonneg` to + -- the product `kB * (T : ℝ)`. · apply mul_nonneg + -- `case hb.ha`: The goal is `⊢ 0 ≤ kB`, which is true by the lemma `kB_nonneg`, since the + -- Boltzmann constant is a positive physical constant. QED for this case. · exact kB_nonneg - · simp [toReal]⟩ + -- `case hb.hb`: The goal is `⊢ 0 ≤ (T : ℝ)`, which is true by `zero_le_real T`, since the + -- real number representation of a `Temperature` is non-negative. QED for this case. + -- All cases have been proven. QED. + · exact zero_le_real T⟩ -/-- The temperature associated with a given inverse temperature `β`. -/ -noncomputable def ofβ (β : ℝ≥0) : Temperature := - ⟨⟨1 / (kB * β), by +/-- Simplification lemma for `Temperature`: + +The definition of `β T` unfolds to its explicit formula in terms of `kB` and `T`. +-/ +@[simp] +lemma β_eq (T : Temperature) : β T = + ⟨1 / (kB * (T : ℝ)), by apply div_nonneg · exact zero_le_one · apply mul_nonneg · exact kB_nonneg - · exact β.2⟩⟩ + · exact zero_le_real T⟩ := by + -- Since the definition of `β T` in the left-hand side is exactly the same as the right-hand side, + -- this is true by reflexivity of equality (`rfl`). QED. + rfl + +/-- Simplification lemma for `Temperature`: + +Coercing `β T` from `ℝ≥0` to `ℝ` gives the explicit formula `1 / (kB * (T : ℝ))`. +-/ +@[simp] +lemma β_toReal (T : Temperature) : (β T : ℝ) = (1 : ℝ) / (kB * (T : ℝ)) := by + -- We rewrite the goal using the definition of `β` from the previous lemma `β_eq`, which gives us + -- `⊢ ↑⟨1 / (kB * T.toReal), ⋯⟩ = 1 / (kB * T.toReal)`, where `↑` denotes the coercion from `ℝ≥0` + -- to `ℝ`, and `⋯` represents the proof of non-negativity that we can ignore since it does not + -- affect the real value. + rw [β_eq] + -- The coercion from `ℝ≥0` to `ℝ` for the left-hand side gives us the same expression as the + -- right-hand side, since the coercion simply takes the underlying real value. Therefore, both + -- sides are definitionally equal, and we can conclude that they are equal by reflexivity of + -- equality (`rfl`). QED. + rfl + -lemma ofβ_eq : ofβ = fun β => ⟨⟨1 / (kB * β), by +/-- Calculate the temperature associated with a given inverse temperature `β`. +-/ +noncomputable def ofβ (β : ℝ≥0) : Temperature := + -- Given the formula `1 / (kB * β)`, we need to show that this is non-negative to fit the type + -- `Temperature`. + ⟨⟨1 / (kB * β), by + -- To show that `1 / (kB * β)` is non-negative, we apply `div_nonneg`, which requires us to show + -- that the numerator is non-negative and the denominator is non-negative. + apply div_nonneg + -- `case ha`: The goal is `⊢ 0 ≤ 1`, which is true by `zero_le_one`, since `1` is a non-negative + -- real number. QED for this case. + · exact zero_le_one + -- `case hb`: The goal is `⊢ 0 ≤ kB * β`, which we can show by applying `mul_nonneg` to the + -- product `kB * β`. + · apply mul_nonneg + -- `case hb.ha`: The goal is `⊢ 0 ≤ kB`, which is true by the lemma `kB_nonneg`, since the + -- Boltzmann constant is a positive physical constant. + · exact kB_nonneg + -- `case hb.hb`: The goal is `⊢ 0 ≤ β`, which is true by the fact that `β : ℝ≥0` carries the + -- proof of its non-negativity as part of its type. QED for this case. + -- All cases have been proven. QED. + · exact β.property⟩⟩ + +/-- Simplification lemma for `Temperature`: + +The definition of `ofβ` unfolds to its explicit formula in terms of `kB` and `β`. +-/ +@[simp] +lemma ofβ_eq : ofβ = fun (β : ℝ≥0) => ⟨⟨1 / (kB * β), by apply div_nonneg · exact zero_le_one · apply mul_nonneg · exact kB_nonneg - · exact β.2⟩⟩ := by + · exact β.property⟩⟩ := by + -- Since the definition of `ofβ` in the left-hand side is exactly the same as the right-hand side, + -- this is true by reflexivity of equality (`rfl`). QED. rfl +/-- Simplification lemma for `Temperature`: + +Applying `β` to the temperature constructed from `β'` returns `β'`. +-/ @[simp] lemma β_ofβ (β' : ℝ≥0) : β (ofβ β') = β' := by + -- We use `ext` to apply the extensionality lemma for `Temperature`, which reduces the goal to + -- show that the `val` fields of both sides are equal. The goal is now + -- `⊢ ↑(ofβ β').β = ↑β'`, where `↑` denotes the coercion from `ℝ≥0` to `ℝ`. ext - simp [β, ofβ, toReal] + -- We simplify the goal with `simp [β, ofβ, Temperature.toReal]`. The goal is now + -- `⊢ kB * ↑β' * kB⁻¹ = ↑β'`. + simp [β, ofβ, Temperature.toReal] + -- We apply `field_simp [kB_ne_zero]` to reduce the `kB * ↑β' * kB⁻¹` to `↑β'`, as `kB_ne_zero` + -- ensures that `kB` is nonzero and thus the simplification is valid. Since both sides are now + -- `↑β'`, they are definitionally equal without needing to invoke reflexivity of equality. QED. field_simp [kB_ne_zero] +/-- Simplification lemma for `Temperature`: + +Rebuilding a temperature `T` from its inverse temperature `β` gives back the original temperature. +-/ @[simp] lemma ofβ_β (T : Temperature) : ofβ (β T) = T := by + -- We use `ext` to apply the extensionality lemma for `Temperature`, which reduces the goal to + -- show that the `val` fields of both sides are equal. The goal is now + -- `⊢ ↑(ofβ T.β).val = ↑T.val`, where `↑` denotes the coercion from `ℝ≥0` to `ℝ`. ext - change ((1 : ℝ) / (kB * ((β T : ℝ)))) = (T : ℝ) - have : (β T : ℝ) = (1 : ℝ) / (kB * (T : ℝ)) := rfl - simpa [this] using - show (1 / (kB * (1 / (kB * (T : ℝ))))) = (T : ℝ) from by - field_simp [kB_ne_zero] + -- We simplify the goal with `simp [β, ofβ, Temperature.toReal]`. The goal is now + -- `⊢ kB * ↑T.val * kB⁻¹ = ↑T.val`. + simp [β, ofβ, Temperature.toReal] + -- We apply `field_simp [kB_ne_zero]` to reduce the `kB * ↑T.val * kB⁻¹` to `↑T.val`, as + -- `kB_ne_zero` ensures that `kB` is nonzero and thus the simplification is valid. Since both + -- sides are now `↑T.val`, they are definitionally equal without needing to invoke reflexivity of + -- equality. QED. + field_simp [kB_ne_zero] -/-- Positivity of `β` from positivity of temperature. -/ -lemma beta_pos (T : Temperature) (hT_pos : 0 < T.val) : 0 < (T.β : ℝ) := by - unfold Temperature.β - have h_prod : 0 < (kB : ℝ) * T.val := mul_pos kB_pos hT_pos - simpa [Temperature.β] using inv_pos.mpr h_prod +/-- Lemma for `Temperature`: -/-! ### Regularity of `ofβ` -/ +The inverse temperature `β` is strictly positive when temperature `T` is strictly positive. +-/ +lemma β_pos (T : Temperature) (h_T_pos : 0 < T.val) : 0 < (T.β : ℝ) := by + -- We simplify the goal with `simp [Temperature.β]`, which unfolds the definition of `β` and gives + -- us the goal `⊢ 0 < T.toReal⁻¹ * kB⁻¹`. + simp [Temperature.β] + -- We apply `mul_pos` to show that the product `T.toReal⁻¹ * kB⁻¹` is positive by showing that + -- both factors are positive. + apply mul_pos + -- `case ha`: The goal is `⊢ 0 < T.toReal⁻¹`, which we can rewrite using `inv_eq_one_div` to get + -- `⊢ 0 < 1 / T.toReal`. Then, we rewrite the goal using `one_div_pos`, which states that + -- `1 / a > 0` if and only if `a > 0`. This gives us the goal `⊢ 0 < T.toReal`. + · rw [inv_eq_one_div, one_div_pos] + -- The goal is now `⊢ 0 < T.toReal`, which is true by the fact that `T.toReal` is defined as + -- `NNReal.toReal T.val`, and since `T.val` is strictly positive (given by `h_T_pos`), its real + -- representation is also strictly positive. QED for this case. + exact h_T_pos + -- `case hb`: The goal is `⊢ 0 < kB⁻¹`, which we can rewrite using `inv_eq_one_div` to get + -- `⊢ 0 < 1 / kB`. Then, we rewrite the goal using `one_div_pos`, which states that `1 / a > 0` + -- if and only if `a > 0`. This gives us the goal `⊢ 0 < kB`. + · rw [inv_eq_one_div, one_div_pos] + -- The goal is now `⊢ 0 < kB`, which is true by the lemma `kB_pos`, since the Boltzmann constant + -- is a positive physical constant. QED for this case. + -- All cases have been proven. QED. + exact kB_pos + +/-! ### Regularity of `ofβ` === TODO TIL THE END OF THE FILE -/ open Filter Topology +/-- Helper lemma: The denominator `kB * b` used in `ofβ` is nonnegative. + +- Premises: + - `b` of type `ℝ≥0`: The inverse temperature input. + +- Conclusion: + - The conclusion is `0 ≤ kB * (b : ℝ)`: The denominator in the formula for `ofβ` is nonnegative. + +- Proof: + - We apply `mul_nonneg` to the product `kB * (b : ℝ)`. + - The first factor is nonnegative by `kB_nonneg`. + - The second factor is nonnegative because `b : ℝ≥0` carries the proof `b.property : 0 ≤ (b : ℝ)`. QED. +-/ +private lemma ofβ_den_nonneg (b : ℝ≥0) : 0 ≤ kB * (b : ℝ) := by + apply mul_nonneg + · exact kB_nonneg + · exact b.property + +/-- Helper lemma: The real-valued expression `1 / (kB * b)` is nonnegative. + +- Premises: + - `b` of type `ℝ≥0`: The inverse temperature input. + +- Conclusion: + - The conclusion is `0 ≤ (1 : ℝ) / (kB * (b : ℝ))`: The real-valued formula used by `ofβ` is nonnegative. + +- Proof: + - We apply `div_nonneg`. + - The numerator is nonnegative by `zero_le_one`. + - The denominator is nonnegative by `ofβ_den_nonneg b`. QED. +-/ +private lemma ofβ_real_nonneg (b : ℝ≥0) : 0 ≤ (1 : ℝ) / (kB * (b : ℝ)) := by + apply div_nonneg + · exact zero_le_one + · exact ofβ_den_nonneg b + +/-- Helper lemma: Continuity at a positive point for the real formula `(t : ℝ) ↦ (1 : ℝ) / (kB * t)`. + +- Premises: + - `x` of type `ℝ≥0`: The point where continuity is evaluated. + - `h_x_pos : 0 < x`: A proof that `x` is strictly positive. + +- Conclusion: + - The conclusion is `ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ)`. + +- Proof: + - We refine the goal using `ContinuousAt.div₀`, which requires us to prove continuity of the numerator and denominator separately: + - Case refine_1: `⊢ ContinuousAt (fun t => 1) ↑x`. + - This is true because constant functions are continuous everywhere. We use `fun_prop` to establish this. + - Case refine_2: `⊢ ContinuousAt (HMul.hMul kB) ↑x`. + - This is true because multiplication by a constant is continuous everywhere. We use `fun_prop` to establish this. + - Case refine_3: `⊢ kB * ↑x ≠ 0`. + - We have the hypothesis `h_x_ne_zero : (x : ℝ) ≠ 0` derived from `ne_of_gt h_x_pos`; which means: "Given a and b, if a > b, then a ≠ b" - and since we have `0 < x`, we conclude `x ≠ 0`. + - We then use `mul_ne_zero kB_ne_zero h_x_ne_zero` to conclude that the product `kB * (x : ℝ)` is nonzero, since both factors are nonzero. QED. +-/ +private lemma ofβ_realExpr_continuousAt_real (x : ℝ≥0) (h_x_pos : 0 < x) : ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ) := by + refine ContinuousAt.div₀ ?_ ?_ ?_ + · fun_prop + · fun_prop + · have h_x_ne_zero : (x : ℝ) ≠ 0 := by + exact (ne_of_gt h_x_pos) + exact mul_ne_zero kB_ne_zero h_x_ne_zero + +/-- Helper lemma: Continuity at a positive point for the same formula on `ℝ≥0`. + +- Premises: + - `x` of type `ℝ≥0`: The point where continuity is evaluated. + - `h_x_pos : 0 < x`: A proof that `x` is strictly positive. + +- Conclusion: + - The conclusion is `ContinuousAt (fun (b : ℝ≥0) => (1 : ℝ) / (kB * (b : ℝ))) x`. + +- Proof: + - Call the function to be proved continuous `f : ℝ≥0 → ℝ` defined by `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`. + - This is the same as the function in the goal, but we give it a name for clarity. + - We define `g : ℝ → ℝ` as `g (t : ℝ) := (1 : ℝ) / (kB * t)`, which is the same formula but defined on `ℝ`. + - We define `h : ℝ≥0 → ℝ` as `h (b : ℝ≥0) := (b : ℝ)`, which is the coercion from `ℝ≥0` to `ℝ`. + - We then prove that `f = g ∘ h` by simplifying both sides and showing they are equal. + - This is done by `rfl`, since both sides are definitionally equal. + - We then prove that `g` is continuous at `x : ℝ` using the previous lemma `ofβ_realExpr_continuousAt_real x h_x_pos`, resulting in the hypothesis `h_continuousAt_real`. + - We also prove that `h` is continuous at `x : ℝ≥0` using `continuous_subtype_val.continuousAt`, which states that the coercion from a subtype to its parent type is continuous at every point, resulting in the hypothesis `h_continuousAt_subtype`. + - Finally, we conclude that `f` is continuous at `x` by using the composition of continuous functions: `h_continuousAt_real.comp h_continuousAt_subtype`. QED. +-/ +private lemma ofβ_realExpr_continuousAt_nnreal (x : ℝ≥0) (h_x_pos : 0 < x): ContinuousAt (fun (b : ℝ≥0) => (1 : ℝ) / (kB * b)) x := by + let f : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (1 : ℝ) / (kB * b) + let g : ℝ → ℝ := fun (t : ℝ) => (1 : ℝ) / (kB * t) + let h : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (b : ℝ) + have f_eq_g_comp_h : f = (g ∘ h) := by + rfl + have h_continuousAt_real : ContinuousAt g (x : ℝ) := ofβ_realExpr_continuousAt_real x h_x_pos + have h_continuousAt_subtype : ContinuousAt h (x : ℝ≥0) := continuous_subtype_val.continuousAt + exact h_continuousAt_real.comp h_continuousAt_subtype + +/-- Helper lemma: Continuity at a positive point for the `ℝ≥0`-valued `val` component of `ofβ`. + +- Premises: + - `x` of type `ℝ≥0`: The point where continuity is evaluated. + - `h_x_pos : 0 < x`: A proof that `x` is strictly positive. + +- Conclusion: + - The conclusion is `ContinuousAt (fun (b : ℝ≥0) => ((ofβ b).val : ℝ≥0)) x`. + +- Proof: + - We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`, which is the real-valued formula used by `ofβ`. + - Then, we prove that `f` is continuous at `x` using the previous lemma `ofβ_realExpr_continuousAt_nnreal x h_x_pos`, resulting in the hypothesis `h_f_continuousAt`. + - Next, we prove that `f` is nonnegative for all `b : ℝ≥0` using the lemma `ofβ_real_nonneg b`, resulting in the hypothesis `h_f_nonneg`. + - We then define `g : ℝ≥0 → ℝ≥0` as `g (b : ℝ≥0) := ⟨f b, h_f_nonneg b⟩`, which is the same formula as `f` but with codomain restricted to `ℝ≥0`. + - We prove that `g` is continuous at `x` by using the fact that if a real-valued function is continuous, then its codomain-restricted version is also continuous. This gives us the hypothesis `h_g_continuousAt`. + - Finally, we conclude that the `val` component of `ofβ` is continuous at `x` by using the hypothesis `h_g_continuousAt`, since `g` is definitionally equal to the function we want to prove continuous. QED. +-/ +private lemma ofβ_val_continuousAt (x : ℝ≥0) (h_x_pos : 0 < x) : ContinuousAt (fun (b : ℝ≥0) => ((ofβ b).val : ℝ≥0)) x := by + let f : ℝ≥0 → ℝ := fun b => (1 : ℝ) / (kB * b) + have h_continuousAt_nnreal : ContinuousAt f x := by + exact ofβ_realExpr_continuousAt_nnreal x h_x_pos + have h_f_nonneg : ∀ b : ℝ≥0, 0 ≤ f (b : ℝ≥0) := by + intro b + exact ofβ_real_nonneg b + let g : ℝ≥0 → ℝ≥0 := fun b => (⟨f b, h_f_nonneg b⟩ : ℝ≥0) + have h_g_continuousAt : ContinuousAt g x := by + exact h_continuousAt_nnreal.codRestrict h_f_nonneg + exact h_g_continuousAt + +/-- Helper lemma: the topology on `Temperature` is induced by the coercion to `ℝ≥0`. + +- Premises: + - None. + +- Conclusion: + - The conclusion is `Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0))`. + +- Proof: + - This is immediate from the topology instance definition, which is exactly `induced` by this coercion map. Therefore the witness is `⟨rfl⟩`. QED. +-/ +private lemma temperature_val_isInducing : Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0)) := by + exact ⟨rfl⟩ + +/-- Helper lemma: continuity of `ofβ` at every strictly positive input. + +- Premises: + - `x` of type `ℝ≥0`: The point where continuity is evaluated. + - `h_x_pos : 0 < x`: A proof that the point is strictly positive. + +- Conclusion: + - The conclusion is `ContinuousAt (ofβ : ℝ≥0 → Temperature) x`. + +- Proof: + - We refine the goal using `temperature_val_isInducing.continuousAt_iff`, which states that continuity of a function into `Temperature` can be checked by continuity of its composition with the coercion to `ℝ≥0`. + - The goal is now `⊢ ContinuousAt ((fun T => T.val) ∘ ofβ) x`. + - This is exactly the content of the previous lemma `ofβ_val_continuousAt x h_x_pos`, so we apply that to conclude. QED. +-/ +private lemma ofβ_continuousAt_of_pos (x : ℝ≥0) (h_x_pos : 0 < x) : ContinuousAt (ofβ : ℝ≥0 → Temperature) x := by + refine (temperature_val_isInducing.continuousAt_iff).mpr ?_ + exact ofβ_val_continuousAt x h_x_pos + +/-- Lemma: The function `ofβ` is continuous on the interval `(0, ∞)`. + +- Premises: + - None. + +- Conclusion: + - The conclusion is `ContinuousOn (ofβ : ℝ≥0 → Temperature) (Set.Ioi 0)`. + +- Proof: + - We refine the goal using `continuousOn_of_forall_continuousAt`, which reduces continuity on a set to continuity at every point in that set. + - The goal is now `⊢ ∀ x ∈ Set.Ioi 0, ContinuousAt ofβ x`. + - We introduce `x : ℝ≥0` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. + - From `h_x_in_set`, we derive `h_x_pos : 0 < x` by: + - Simplifying the definition of `Set.Ioi 0`, which states that `x ∈ Set.Ioi 0` means `0 < x`. + - Extracting the strict inequality `0 < x` from this definition. + - Given `x : ℝ≥0` and `h_x_pos : 0 < x`, we can prove the goal with `ofβ_continuousAt_of_pos x h_x_pos`. QED. +-/ lemma ofβ_continuousOn : ContinuousOn (ofβ : ℝ≥0 → Temperature) (Set.Ioi 0) := by - rw [ofβ_eq] refine continuousOn_of_forall_continuousAt ?_ - intro x hx - have h1 : ContinuousAt (fun t : ℝ => 1 / (kB * t)) x.1 := by - refine ContinuousAt.div₀ ?_ ?_ ?_ - · fun_prop - · fun_prop - · simp - constructor - · exact kB_ne_zero - · exact ne_of_gt hx - have hℝ : ContinuousAt (fun b : ℝ≥0 => (1 : ℝ) / (kB * (b : ℝ))) x := - h1.comp (continuous_subtype_val.continuousAt) - have hNN : - ContinuousAt (fun b : ℝ≥0 => - (⟨(1 : ℝ) / (kB * (b : ℝ)), - by - have hb : 0 ≤ kB * (b : ℝ) := - mul_nonneg kB_nonneg (by exact_mod_cast (show 0 ≤ b from b.2)) - exact div_nonneg zero_le_one hb⟩ : ℝ≥0)) x := - hℝ.codRestrict (fun b => by - have hb : 0 ≤ kB * (b : ℝ) := - mul_nonneg kB_nonneg (by exact_mod_cast (show 0 ≤ b from b.2)) - exact div_nonneg zero_le_one hb) - have hind : Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0)) := ⟨rfl⟩ - have : Tendsto (fun b : ℝ≥0 => ofβ b) (𝓝 x) (𝓝 (ofβ x)) := by - simp [hind.nhds_eq_comap, ofβ_eq] - simp_all only [Set.mem_Ioi, one_div, mul_inv_rev, val_eq_coe] - exact hNN - exact this - -lemma ofβ_differentiableOn : - DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0) := by - refine DifferentiableOn.congr (f := fun x => 1 / (kB * x)) ?_ ?_ + intro x h_x_in_set + have h_x_pos : 0 < x := by + simp at h_x_in_set + exact h_x_in_set + exact ofβ_continuousAt_of_pos x h_x_pos + +/-- Lemma: The function `ofβ` is differentiable on the interval `(0, ∞)`. + +- Premises: + - None. + +- Conclusion: + - The conclusion is `DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0)`: The function mapping `x` to the real-valued `val` component of `ofβ (Real.toNNReal x)` is differentiable on the interval `(0, ∞)`. + +- Proof: + - We refine the goal using `DifferentiableOn.congr`, which allows us to prove differentiability by showing that the function is equal to a simpler function that we can easily differentiate. We now have two cases: + - Case refine_1: `⊢ DifferentiableOn ℝ (fun x => 1 / (kB * x)) (Set.Ioi 0)`. + - We further refine this using `DifferentiableOn.fun_div`, which requires us to prove differentiability of the numerator and denominator separately, and that the denominator is nonzero on the set: + - Case refine_1.refine_1: `⊢ DifferentiableOn ℝ (fun x => 1) (Set.Ioi 0)`. + - This is true because constant functions are differentiable everywhere. We use `fun_prop` to establish this. + - Case refine_1.refine_2: `⊢ DifferentiableOn ℝ (HMul.hMul kB) (Set.Ioi 0)`. + - This is true because multiplication by a constant is differentiable everywhere. We use `fun_prop` to establish this. + - Case refine_1.refine_3: `⊢ ∀ x ∈ Set.Ioi 0, kB * x ≠ 0`. + - We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. The goal is now `⊢ kB * x ≠ 0`. + - We derive `h_x_ne_zero : x ≠ 0` from `h_x_in_set` by noting that if `x` is strictly greater than `0`, then it cannot be equal to `0`. + - We then apply `mul_ne_zero` to conclude that `kB * x` is nonzero. + - The first factor `kB` is nonzero by `kB_ne_zero`. + - The second factor `x` is nonzero by `h_x_ne_zero`. + - This completes the proof of this case. + - Case refine_2: `⊢ ∀ x ∈ Set.Ioi 0, ↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. + - We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. The goal is now `↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. + - We derive `h_x_pos : 0 < x` from `h_x_in_set` by simplifying the definition of `Set.Ioi 0` to extract the strict inequality `0 < x`. + - We also derive `h_x_nonneg : 0 ≤ x` from `h_x_pos` by noting that if `x` is strictly greater than `0`, then it can be considered as "greater than or equal to `0`" as well (since `0 < x` implies `0 ≤ x`). + - We then simplify the goal using `simp` to get a new goal that is a disjunction: `⊢ 0 ≤ x ∨ kB = 0`. + - We only have to prove the left disjunct `0 ≤ x` since `kB` is nonzero by `kB_ne_zero` (thus the right disjunct is false). + - We have already established `h_x_nonneg : 0 ≤ x`, so we can conclude this case by left disjunction and using `h_x_nonneg`. + - This completes the proof of this case. + - With both cases proved, we conclude that the original function is differentiable on the interval `(0, ∞)`. QED. +-/ +lemma ofβ_differentiableOn : DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0) := by + refine DifferentiableOn.congr (f := fun (x : ℝ) => (1 : ℝ) / (kB * x)) ?_ ?_ · refine DifferentiableOn.fun_div ?_ ?_ ?_ · fun_prop · fun_prop - · intro x hx - have hx0 : x ≠ 0 := ne_of_gt (by simpa using hx) - simp [mul_eq_zero, kB_ne_zero, hx0] - · intro x hx - simp at hx - have hx' : 0 < x := by simpa using hx - simp [ofβ_eq, hx'.le, Real.toNNReal, NNReal.coe_mk] + · intro x h_x_in_set + have h_x_ne_zero : x ≠ 0 := by + exact ne_of_gt h_x_in_set + apply mul_ne_zero + · exact kB_ne_zero + · exact h_x_ne_zero + · intro x h_x_in_set + have h_x_pos : 0 < x := by + simp at h_x_in_set + exact h_x_in_set + have h_x_nonneg : 0 ≤ x := by + simpa using h_x_pos.le + simp + left + simp [h_x_nonneg] /-! ### Convergence -/ open Filter Topology -/-- Eventually, `ofβ β` is positive as β → ∞`. -/ +/-- Lemma: The function `ofβ` produces strictly positive real-valued temperatures for sufficiently large inverse temperature β. + +- Premises: + - None. + +- Conclusion: + - The conclusion is `∀ᶠ b : ℝ≥0 in atTop, ((Temperature.ofβ b : Temperature) : ℝ) > 0`: For sufficiently large values of the inverse temperature `b`, the real-valued representation of the temperature `ofβ b` is strictly positive. + +- Proof: + - We start by proving that for sufficiently large `b : ℝ≥0`, we have `1 ≤ b` using `Filter.eventually_ge_atTop 1`, which states that eventually, all elements of the filter at infinity are greater than or equal to `1`. This gives us the hypothesis `h_eventually_b_ge_one`. + - We then refine the goal using `h_eventually_b_ge_one.mono`, which allows us to prove the desired property for all `b` that satisfy `1 ≤ b`. The new goal is now `⊢ ∀ (x : ℝ≥0), 1 ≤ x → (ofβ x).toReal > 0`. + - We introduce `b : ℝ≥0` and the hypothesis `h_b_ge_one : 1 ≤ b` from the goal. The goal is now `⊢ (ofβ b).toReal > 0`. + - The goal is now `⊢ (1 : ℝ) / (kB * (↑b : ℝ)) > 0`. + - We derive `h_b_pos : 0 < (b : ℝ)` using `zero_lt_one.trans_le h_b_ge_one`, which states that if `0 < 1` and `1 ≤ b`, then `0 < b`. + - We derive `h_denominator_pos : 0 < kB * (b : ℝ)` using `mul_pos kB_pos h_b_pos`, which states that if `kB` is positive (proven by `kB_pos`) and `b` is positive (proven by `h_b_pos`), then their product is positive. + - We derive `h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ))` using `one_div_pos.mpr h_denominator_pos`, which states that if the denominator is positive, then the reciprocal is also positive. + - We then unfold the definition of `ofβ` to express `(ofβ b).toReal` as `(1 : ℝ) / (kB * (↑b : ℝ))`. + - Finally, we conclude that the goal `(1 : ℝ) / (kB * (b : ℝ)) > 0` is true by `h_quotient_pos`. QED. +-/ lemma eventually_pos_ofβ : ∀ᶠ b : ℝ≥0 in atTop, ((Temperature.ofβ b : Temperature) : ℝ) > 0 := by - have hge : ∀ᶠ b : ℝ≥0 in atTop, (1 : ℝ≥0) ≤ b := Filter.eventually_ge_atTop 1 - refine hge.mono ?_ - intro b hb - have hbpos : 0 < (b : ℝ) := (zero_lt_one.trans_le hb) - have hden : 0 < kB * (b : ℝ) := mul_pos kB_pos hbpos - have : 0 < (1 : ℝ) / (kB * (b : ℝ)) := one_div_pos.mpr hden - simpa [Temperature.ofβ, one_div, Temperature.toReal] using this - -/-- General helper: for any `a > 0`, we have `1 / (a * b) → 0` as `b → ∞` in `ℝ≥0`. -/ -private lemma tendsto_const_inv_mul_atTop (a : ℝ) (ha : 0 < a) : - Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by - refine Metric.tendsto_nhds.2 ?_ - intro ε hε - have hεpos : 0 < ε := hε - let Breal : ℝ := (1 / (a * ε)) + 1 - have hBpos : 0 < Breal := by - have : 0 < (1 / (a * ε)) := by - have : 0 < a * ε := mul_pos ha hεpos - exact one_div_pos.mpr this - linarith - let B : ℝ≥0 := ⟨Breal, le_of_lt hBpos⟩ - have h_ev : ∀ᶠ b : ℝ≥0 in atTop, b ≥ B := Filter.eventually_ge_atTop B - refine h_ev.mono ?_ - intro b hb - have hBposR : 0 < (B : ℝ) := hBpos - have hbposR : 0 < (b : ℝ) := by - have hBB : (B : ℝ) ≤ (b : ℝ) := by exact_mod_cast hb - exact lt_of_lt_of_le hBposR hBB - have hb0 : 0 < (a * (b : ℝ)) := mul_pos ha hbposR - have hB0 : 0 < (a * (B : ℝ)) := mul_pos ha hBposR - have hmono : (1 : ℝ) / (a * (b : ℝ)) ≤ (1 : ℝ) / (a * (B : ℝ)) := by - have hBB : (B : ℝ) ≤ (b : ℝ) := by exact_mod_cast hb - have hden_le : (a * (B : ℝ)) ≤ (a * (b : ℝ)) := - mul_le_mul_of_nonneg_left hBB (le_of_lt ha) - simpa [one_div] using one_div_le_one_div_of_le hB0 hden_le - have hB_gt_base : (1 / (a * ε)) < (B : ℝ) := by - simp [B, Breal] - have hden_gt : (1 / ε) < (a * (B : ℝ)) := by - have h' := mul_lt_mul_of_pos_left hB_gt_base ha - have hane : a ≠ 0 := ne_of_gt ha - have hx' : a * (ε⁻¹ * a⁻¹) = (1 / ε) := by - have : a * (ε⁻¹ * a⁻¹) = ε⁻¹ := by - simp [mul_comm, hane] - simpa [one_div] using this - simpa [hx'] using h' - have hpos : 0 < (1 / ε) := by simpa [one_div] using inv_pos.mpr hεpos - have hBbound : (1 : ℝ) / (a * (B : ℝ)) < ε := by - have := one_div_lt_one_div_of_lt hpos hden_gt - simpa [one_div, inv_div] using this - set A : ℝ := (1 : ℝ) / (a * (b : ℝ)) with hA - have hA_nonneg : 0 ≤ A := by - have : 0 ≤ a * (b : ℝ) := - mul_nonneg (le_of_lt ha) (by exact_mod_cast (show 0 ≤ b from b.2)) - simpa [hA] using div_nonneg zero_le_one this - have hxlt : A < ε := by - have := lt_of_le_of_lt hmono hBbound - simpa [hA] using this - have hAbs : |A| < ε := by - simpa [abs_of_nonneg hA_nonneg] using hxlt - have hAbs' : |A - 0| < ε := by simpa [sub_zero] using hAbs - have hdist : dist A 0 < ε := by simpa [Real.dist_eq] using hAbs' - simpa [Real.dist_eq, hA, one_div, mul_comm, mul_left_comm, mul_assoc] using hdist - -/-- Core convergence: as β → ∞, `toReal (ofβ β) → 0` in `ℝ`. -/ -lemma tendsto_toReal_ofβ_atTop : - Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) - atTop (𝓝 (0 : ℝ)) := by - have hform : - (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) - = (fun b : ℝ≥0 => (1 : ℝ) / (kB * (b : ℝ))) := by - funext b; simp [Temperature.ofβ, Temperature.toReal] - have hsrc : - Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (kB * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := - tendsto_const_inv_mul_atTop kB kB_pos - simpa [hform] using hsrc + have h_eventually_b_ge_one : ∀ᶠ b : ℝ≥0 in atTop, (1 : ℝ≥0) ≤ b := Filter.eventually_ge_atTop 1 + refine h_eventually_b_ge_one.mono ?_ + intro b h_b_ge_one + have h_b_pos : 0 < (b : ℝ) := by + exact zero_lt_one.trans_le h_b_ge_one + have h_denominator_pos : 0 < kB * (b : ℝ) := by + exact mul_pos kB_pos h_b_pos + have h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ)) := one_div_pos.mpr h_denominator_pos + unfold ofβ + exact h_quotient_pos + +/-- Helper lemma: Positivity of the epsilon-delta bound construction. + +- Premises: + - `a : ℝ`: A positive real number (typically the constant in the denominator). + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `ε : ℝ`: A positive epsilon value (from the metric space definition). + - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. + +- Conclusion: + - The conclusion is `0 < (1 / (a * ε)) + 1`: The expression used in the epsilon-delta bound construction is strictly positive. + +- Proof: + - We first prove that `1 / (a * ε)` is positive. + - We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive (proof of `a` and `ε` being positive are given by `h_a_pos` and `h_ε_pos`). + - We then apply `one_div_pos.mpr h_product_pos` to conclude that `1 / (a * ε)` is positive, since the reciprocal of a positive number is also positive. We derive `h_reciprocal_pos : 0 < (1 / (a * ε))` from this. + - Finally, we conclude that `0 < (1 / (a * ε)) + 1` by applying `add_pos h_reciprocal_pos zero_lt_one`, which states that the sum of two positive numbers is positive. Here, `h_reciprocal_pos` provides the positivity of the first term, and `zero_lt_one` provides the positivity of the second term. QED. +-/ +private lemma tendsto_const_inv_mul_bound_pos (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : 0 < (1 / (a * ε)) + 1 := by + have h_reciprocal_pos : 0 < (1 / (a * ε)) := by + have h_product_pos : 0 < a * ε := by + exact mul_pos h_a_pos h_ε_pos + exact one_div_pos.mpr h_product_pos + exact add_pos h_reciprocal_pos zero_lt_one + +/-- Helper lemma: Product positivity via transitivity of ordering. + +- Premises: + - `a : ℝ`: A positive real number. + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `b_lower_bound : ℝ`: A positive lower bound. + - `h_b_lower_bound_pos : 0 < b_lower_bound`: Hypothesis that `b_lower_bound` is strictly positive. + - `b : ℝ`: A real number greater than or equal to `b_lower_bound`. + - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is at least `b_lower_bound`. + +- Conclusion: + - The conclusion is `0 < a * b`: The product `a * b` is strictly positive. + +- Proof: + - From `0 < b_lower_bound ≤ b`, we obtain `0 < b` by transitivity using `lt_of_lt_of_le` applied to `h_b_lower_bound_pos` (`0 < b_lower_bound`) and `h_b_lower_bound_le_b` (`b_lower_bound ≤ b`). + - Then apply `mul_pos` to `h_a_pos` and `h_b_pos` to get `0 < a * b`. QED. +-/ +private lemma tendsto_const_inv_mul_product_pos_of_le (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : 0 < a * b := by + have h_b_pos : 0 < b := lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b + exact mul_pos h_a_pos h_b_pos + +/-- Helper lemma: Antitonicity of reciprocal function with constant multiplier. + +- Premises: + - `a : ℝ`: A positive constant multiplier. + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `b_lower_bound : ℝ`: A positive lower bound value. + - `b : ℝ`: A value greater than or equal to `b_lower_bound`. + - `h_product_b_lower_bound_pos : 0 < a * b_lower_bound`: Hypothesis that the product `a * b_lower_bound` is strictly positive. + - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is at least `b_lower_bound`. + +- Conclusion: + - The conclusion is `(1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)`: The reciprocal function `x ↦ 1 / (a * x)` is antitone (decreasing). + +- Proof: + - First, we derive `h_denom_le : (a * b_lower_bound) ≤ (a * b)` by applying `mul_le_mul_of_nonneg_left` to `h_b_lower_bound_le_b` and the nonnegativity of `a` (which follows from its positivity `h_a_pos`). + - Then we apply `one_div_le_one_div_of_le` to `h_product_b_lower_bound_pos` and `h_denom_le` to conclude that the reciprocal of the larger denominator is less than or equal to the reciprocal of the smaller denominator, which establishes the antitonicity. QED. +-/ +private lemma tendsto_const_inv_mul_reciprocal_antitone (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_product_b_lower_bound_pos : 0 < a * b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by + have h_denom_le : (a * b_lower_bound) ≤ (a * b) := by + exact mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos) + exact one_div_le_one_div_of_le h_product_b_lower_bound_pos h_denom_le + +/-- Helper lemma: Evaluating the function at the constructed bound yields a value less than `ε`. + +- Premises: + - `a : ℝ`: A positive constant. + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `ε : ℝ`: A positive epsilon value. + - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. + +- Conclusion: + - The conclusion is `(1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε`: Evaluating the function at the constructed bound yields a value less than `ε`, which is crucial for the epsilon-delta argument in proving convergence. + +- Proof: + - We first simplify the expression by performing field simplification with `field_simp` to rewrite the goal into `⊢ 1 < 1 + a * ε`. + - We then simplify further using `simp` to reduce the goal to `⊢ 0 < a * ε`. + - We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive. This gives us the desired inequality. QED. +-/ +private lemma tendsto_const_inv_mul_at_bound_lt_epsilon (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : (1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε := by + field_simp + simp + have h_product_pos : 0 < a * ε := by + exact mul_pos h_a_pos h_ε_pos + exact h_product_pos + + +/-- Helper lemma: Conversion from nonnegative inequality to metric space distance. + +- Premises: + - `x : ℝ`: A real number. + - `h_x_nonneg : 0 ≤ x`: Hypothesis that `x` is nonnegative. + - `ε : ℝ`: A bound value. + - `h_x_lt_ε : x < ε`: Hypothesis that `x` is strictly less than `ε`. + +- Conclusion: + - The conclusion is `dist x 0 < ε`: The metric space distance from `x` to `0` is less than `ε`. + +- Proof: + - We first derive `h_abs_lt : |x| < ε` by calling `simpa [abs_of_nonneg h_x_nonneg] using h_x_lt_ε`, which simplifies the absolute value of `x` using the fact that `x` is nonnegative, and then applies the hypothesis that `x < ε`. + - We then rewrite the goal `dist x 0 < ε` using `Real.dist_eq` to express the distance in terms of absolute value (`dist x 0` is equal to `|x - 0|`), and use `sub_zero` to simplify this to `|x| < ε`. + - Finally, we conclude that `|x| < ε` is true by `h_abs_lt`. QED. +-/ +private lemma tendsto_const_inv_mul_nonneg_to_dist (x ε : ℝ) (h_x_nonneg : 0 ≤ x) (h_x_lt_ε : x < ε) : dist x 0 < ε := by + have h_abs_lt : |x| < ε := by + simpa [abs_of_nonneg h_x_nonneg] using h_x_lt_ε + rw [Real.dist_eq, sub_zero] + exact h_abs_lt + +/-- Helper lemma: Given a lower bound on `b` that ensures the function value is less than `ε`, we can conclude that for any `b` greater than or equal to that lower bound, the function value is nonnegative and less than `ε`. + +- Premises: + - `a : ℝ`: A positive constant. + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `ε : ℝ`: A positive epsilon value. + - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. + - `b_lower_bound : ℝ`: A positive lower bound for `b`. + - `h_b_lower_bound_pos : 0 < b_lower_bound`: Hypothesis that the lower bound is strictly positive. + - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is greater than or equal to the lower bound. + - `h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε`: Hypothesis that the function value at the lower bound is less than `ε`. + +- Conclusion: + - The conclusion is `0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε`: For any `b` greater than or equal to the lower bound, the value of the function `1 / (a * b)` is nonnegative and less than `ε`. + +- Proof: + - We first derive `h_prod_lower_pos : 0 < a * b_lower_bound` using `mul_pos h_a_pos h_b_lower_bound_pos`, which states that the product of two positive numbers is positive. + - We then derive `h_prod_pos : 0 < a * b` using the previous lemma `tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b`, which states that if `b` is greater than or equal to a positive lower bound, then the product `a * b` is also positive. + - Next, we derive `h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)` using the previous lemma `tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b h_a_pos h_prod_lower_pos h_b_lower_bound_le_b`, which states that the reciprocal function is antitone. + - We then derive `h_lt : (1 : ℝ) / (a * b) < ε` using `lt_of_le_of_lt h_rec_le h_at_bound_lt`, which states that if `1 / (a * b)` is less than or equal to `1 / (a * b_lower_bound)` and `1 / (a * b_lower_bound)` is less than `ε`, then `1 / (a * b)` is also less than `ε`. + - Finally, we derive `h_nonneg : 0 ≤ (1 : ℝ) / (a * b)` using `div_nonneg zero_le_one (le_of_lt h_prod_pos)`, which states that the reciprocal of a positive number is nonnegative. + - We conclude that `0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` by combining `h_nonneg` and `h_lt`. QED. +-/ +private lemma tendsto_const_inv_mul_nonneg_and_lt_of_bound (a ε b_lower_bound b : ℝ) (h_a_pos : 0 < a)(h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := by + have h_prod_lower_pos : 0 < a * b_lower_bound := by + exact mul_pos h_a_pos h_b_lower_bound_pos + have h_prod_pos : 0 < a * b := by + exact tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b + have h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by + exact tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b h_a_pos h_prod_lower_pos h_b_lower_bound_le_b + have h_lt : (1 : ℝ) / (a * b) < ε := by + exact lt_of_le_of_lt h_rec_le h_at_bound_lt + have h_nonneg : 0 ≤ (1 : ℝ) / (a * b) := by + exact div_nonneg zero_le_one (le_of_lt h_prod_pos) + exact ⟨h_nonneg, h_lt⟩ + +/-- Helper lemma: Given a lower bound on `b` that ensures the function value is less than `ε`, we can conclude that for any `b` greater than or equal to that lower bound, the distance from the function value to `0` is less than `ε`. + +- Premises: + - `a : ℝ`: A positive constant. + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `ε : ℝ`: A positive epsilon value. + - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. + - `b_lower_bound : ℝ`: A positive lower bound for `b`. + - `h_b_lower_bound_pos : 0 < b_lower_bound`: Hypothesis that the lower bound is strictly positive. + - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is greater than or equal to the lower bound. + - `h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε`: Hypothesis that the function value at the lower bound is less than `ε`. + +- Conclusion: + - The conclusion is `dist ((1 : ℝ) / (a * b)) (0 : ℝ) < ε`: The distance from the function value `1 / (a * b)` to `0` is less than `ε`. + +- Proof: + - We first derive `h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` using the previous lemma `tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt`, which states that for any `b` greater than or equal to the lower bound, the function value is nonnegative and less than `ε`. + - We then apply `tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε h_nonneg_and_lt.left h_nonneg_and_lt.right` to conclude that the distance from the function value to `0` is less than `ε`, using the fact that if a value is nonnegative and less than `ε`, then its distance to `0` is also less than `ε`. QED. +-/ +private lemma tendsto_const_inv_mul_dist_lt_of_bound (a ε b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : dist ((1 : ℝ) / (a * b)) (0 : ℝ) < ε := by + have h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := + tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b + h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt + exact tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε h_nonneg_and_lt.left h_nonneg_and_lt.right + +/-- Helper lemma: As `b` tends to infinity, the distance from the function value `1 / (a * b)` to `0` becomes less than any positive `ε` for sufficiently large `b`. + +- Premises: + - `a : ℝ`: A positive constant. + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `ε : ℝ`: A positive epsilon value. + - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. + +- Conclusion: + - The conclusion is `∀ᶠ b : ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε`: For sufficiently large values of `b`, the distance from the function value `1 / (a * b)` to `0` is less than `ε`. + +- Proof: + - We first construct a real number `B_real` defined as `(1 / (a * ε)) + 1`, which serves as a candidate lower bound for `b` to ensure that the function value is less than `ε`. + - We then derive `h_B_real_pos : 0 < B_real` using the previous lemma `tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos`, which states that the constructed bound is positive. + - We convert `B_real` to a nonnegative real number `B_nnreal` by taking the nonnegative part of `B_real`, ensuring that it is still positive. + - We derive `h_B_nnreal_pos : 0 < (B_nnreal : ℝ)` from `h_B_real_pos` by noting that the nonnegative part of a positive real number is also positive. + - We then refine the goal using `Filter.eventually_ge_atTop B_nnreal`, which states that eventually, all elements of the filter at infinity are greater than or equal to `B_nnreal`. The goal is now `⊢ ∀ (x : ℝ≥0), B_nnreal ≤ x → dist (1 / (a * ↑x)) 0 < ε`. + - We introduce `b : ℝ≥0` and the hypothesis `h_B_nnreal_le_b : B_nnreal ≤ b` from the goal. The goal is now `⊢ dist (1 / (a * ↑b)) 0 < ε`. + - We derive `h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε` using the previous lemma `tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos`, which states that evaluating the function at the constructed bound yields a value less than `ε`. + - Finally, we apply `tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt` to conclude that the distance from the function value to `0` is less than `ε` for any `b` greater than or equal to the constructed bound. QED. +-/ +private lemma tendsto_const_inv_mul_atTop_eventually_dist_lt (a : ℝ) (h_a_pos : 0 < a) (ε : ℝ) (h_ε_pos : 0 < ε) : ∀ᶠ b : ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε := by + let B_real : ℝ := (1 / (a * ε)) + 1 + have h_B_real_pos : 0 < B_real := by + exact tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos + let B_nnreal : ℝ≥0 := ⟨B_real, le_of_lt h_B_real_pos⟩ + have h_B_nnreal_pos : 0 < (B_nnreal : ℝ) := by simpa [B_nnreal] using h_B_real_pos + refine (Filter.eventually_ge_atTop B_nnreal).mono ?_ + intro b h_B_nnreal_le_b + have h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε := by + exact tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos + exact tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt + +/-- Helper lemma: As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` in the sense of the metric space distance. + +- Premises: + - `a : ℝ`: A positive constant. + - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. + - `ε : ℝ`: A positive epsilon value. + - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. + +- Conclusion: + - The conclusion is `Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ))`: As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` in the sense of the metric space distance. + +- Proof: + - We refine the goal using `Metric.tendsto_nhds.mpr`, which allows us to prove the convergence by showing that for every positive `ε`, the function values are eventually within `ε` of `0`. The new goal is now `⊢ ∀ ε > 0, ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. + - We introduce `ε : ℝ` and the hypothesis `h_ε_pos : 0 < ε`. The goal is now `⊢ ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. + - We apply the previous lemma `tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos` to conclude that for sufficiently large `b`, the distance from the function value to `0` is less than `ε`. QED. +-/ +private lemma tendsto_const_inv_mul_atTop (a : ℝ) (h_a_pos : 0 < a) : Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by + refine Metric.tendsto_nhds.mpr ?_ + intro ε h_ε_pos + exact tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos + +/-- Lemma: As the inverse temperature `β` tends to infinity, the real-valued representation of the temperature `ofβ β` tends to `0` in the sense of the metric space distance. + +- Premises: + - None. + +- Conclusion: + - The conclusion is `Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ))`: As `β` tends to infinity, the real-valued representation of the temperature `ofβ β` tends to `0` in the sense of the metric space distance. + +- Proof: + - We apply the previous lemma `tendsto_const_inv_mul_atTop` with `a` set to `kB` and `h_a_pos` set to `kB_pos`, which states that as `b` tends to infinity, the function value `1 / (kB * b)` tends to `0`. Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. +-/ +lemma tendsto_toReal_ofβ_atTop : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ)) := by + exact tendsto_const_inv_mul_atTop kB kB_pos /-- As β → ∞, T = ofβ β → 0+ in ℝ (within Ioi 0). -/ -lemma tendsto_ofβ_atTop : - Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) - atTop (nhdsWithin 0 (Set.Ioi 0)) := by +lemma tendsto_ofβ_atTop : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (nhdsWithin 0 (Set.Ioi 0)) := by have h_to0 := tendsto_toReal_ofβ_atTop - have h_into : - Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓟 (Set.Ioi (0 : ℝ))) := - tendsto_principal.2 (by simpa using Temperature.eventually_pos_ofβ) + have h_into : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓟 (Set.Ioi (0 : ℝ))) := + tendsto_principal.mpr (by simpa using Temperature.eventually_pos_ofβ) have : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop ((nhds (0 : ℝ)) ⊓ 𝓟 (Set.Ioi (0 : ℝ))) := - tendsto_inf.2 ⟨h_to0, h_into⟩ + tendsto_inf.mpr ⟨h_to0, h_into⟩ simpa [nhdsWithin] using this /-! ### Conversion to and from `ℝ≥0` -/ open Constants -/-- Build a `Temperature` directly from a nonnegative real. -/ -@[simp] def ofNNReal (t : ℝ≥0) : Temperature := ⟨t⟩ +/-- Simplification function: Build a temperature from a nonnegative real number. +- Input: + - `t` of type `ℝ≥0`: The nonnegative real number representing the temperature. +- Output: + - Result of type `Temperature`: The temperature constructed from the nonnegative real number. +-/ @[simp] -lemma ofNNReal_val (t : ℝ≥0) : (ofNNReal t).val = t := rfl +def ofNNReal (t : ℝ≥0) : Temperature := ⟨t⟩ + +/-- Simplification lemma: The `val` field of a temperature constructed from a nonnegative real number `t` is equal to `t`. +- Premises: + - `t` of type `ℝ≥0`: The nonnegative real number used to construct the temperature. +- Conclusion: + - The conclusion is `(ofNNReal t).val = t`: The `val` field of the temperature constructed from `t` is equal to `t`. +- Proof: + - The proof is straightforward as it directly follows from the definition of `ofNNReal`. + - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +-/ @[simp] -lemma coe_ofNNReal_coe (t : ℝ≥0) : ((ofNNReal t : Temperature) : ℝ≥0) = t := rfl +lemma ofNNReal_val (t : ℝ≥0) : (ofNNReal t).val = t := by + rfl +/-- Simplification lemma: Coercing a temperature constructed from a nonnegative real number `t` back to `ℝ≥0` returns `t`. + +- Premises: + - `t` of type `ℝ≥0`: The nonnegative real number used to construct the temperature. +- Conclusion: + - The conclusion is `((ofNNReal t : Temperature) : ℝ≥0) = t`: Coercing the temperature back to `ℝ≥0` returns the original `t`. +- Proof: + - The proof is straightforward as it directly follows from the definition of `ofNNReal` and the coercion. + - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +-/ @[simp] -lemma coe_ofNNReal_real (t : ℝ≥0) : ((⟨t⟩ : Temperature) : ℝ) = t := rfl +lemma coe_ofNNReal_coe (t : ℝ≥0) : ((ofNNReal t : Temperature) : ℝ≥0) = t := by + rfl + +/-- Simplification lemma: Coercing a temperature constructed from a nonnegative real number `t` to `ℝ` returns `t`. -/-- Convenience: build a temperature from a real together with a proof of nonnegativity. -/ +- Premises: + - `t` of type `ℝ≥0`: The nonnegative real number used to construct the temperature. +- Conclusion: + - The conclusion is `((ofNNReal t : Temperature) : ℝ) = t`: Coercing the temperature to `ℝ` returns the original `t`. +- Proof: + - The proof is straightforward as it directly follows from the definition of `ofNNReal` and the coercion. + - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +-/ @[simp] -noncomputable def ofRealNonneg (t : ℝ) (ht : 0 ≤ t) : Temperature := - ofNNReal ⟨t, ht⟩ +lemma coe_ofNNReal_real (t : ℝ≥0) : ((⟨t⟩ : Temperature) : ℝ) = t := by + rfl +/-- Simplification function: Build a temperature from a real number, given a proof that it is nonnegative. + +- Input: + - `t` of type `ℝ`: The real number representing the temperature. + - `h_zero_le_t` of type `0 ≤ t`: A proof that the real number is nonnegative. +- Output: + - Result of type `Temperature`: The temperature constructed from the real number `t`. +-/ @[simp] -lemma ofRealNonneg_val {t : ℝ} (ht : 0 ≤ t) : - (ofRealNonneg t ht).val = ⟨t, ht⟩ := rfl +noncomputable def ofRealNonneg (t : ℝ) (h_zero_le_t : 0 ≤ t) : Temperature := ofNNReal ⟨t, h_zero_le_t⟩ + +/-- Simplification lemma: The `val` field of a temperature constructed from a nonnegative real number `t` is equal to `⟨t, h_zero_le_t⟩`. + +- Premises: + - `t` of type `ℝ` (implicit): The real number used to construct the temperature. + - `h_zero_le_t` of type `0 ≤ t`: A proof that the real number is nonnegative. +- Conclusion: + - The conclusion is `(ofRealNonneg t h_zero_le_t).val = ⟨t, h_zero_le_t⟩`: The `val` field of the temperature constructed from `t` is equal to `⟨t, h_zero_le_t⟩`. +- Proof: + - The proof is straightforward as it directly follows from the definition of `ofRealNonneg`. + - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +-/ +@[simp] +lemma ofRealNonneg_val {t : ℝ} (h_zero_le_t : 0 ≤ t) : (ofRealNonneg t h_zero_le_t).val = ⟨t, h_zero_le_t⟩ := by + rfl /-! ### Calculus relating T and β -/ @@ -274,28 +916,28 @@ open scoped ENNReal /-- Map a real `t` to the inverse temperature `β` corresponding to the temperature `Real.toNNReal t` (`max t 0`), returned as a real number. -/ -noncomputable def betaFromReal (t : ℝ) : ℝ := +noncomputable def βFromReal (t : ℝ) : ℝ := ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) -/-- Explicit closed-form for `Beta_fun_T t` when `t > 0`. -/ -lemma beta_fun_T_formula (t : ℝ) (ht : 0 < t) : - betaFromReal t = 1 / (kB * t) := by +/-- Explicit closed-form for `β_fun_T t` when `t > 0`. -/ +lemma β_fun_T_formula (t : ℝ) (ht : 0 < t) : + βFromReal t = (1 : ℝ) / (kB * t) := by have ht0 : (0 : ℝ) ≤ t := ht.le - have : ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = 1 / (kB * t) := by + have : ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = (1 : ℝ) / (kB * t) := by simp [Temperature.β, Temperature.ofNNReal, Temperature.toReal, Real.toNNReal_of_nonneg ht0, one_div, mul_comm] - simpa [betaFromReal] using this + simpa [βFromReal] using this -/-- On `Ioi 0`, `Beta_fun_T t` equals `1 / (kB * t)`. -/ -lemma beta_fun_T_eq_on_Ioi : - EqOn betaFromReal (fun t : ℝ => 1 / (kB * t)) (Set.Ioi 0) := by +/-- On `Ioi 0`, `β_fun_T t` equals `1 / (kB * t)`. -/ +lemma β_fun_T_eq_on_Ioi : + EqOn βFromReal (fun t : ℝ => (1 : ℝ) / (kB * t)) (Set.Ioi 0) := by intro t ht - exact beta_fun_T_formula t ht + exact β_fun_T_formula t ht -lemma deriv_beta_wrt_T (T : Temperature) (hT_pos : 0 < T.val) : - HasDerivWithinAt betaFromReal (-1 / (kB * (T.val : ℝ)^2)) (Set.Ioi 0) (T.val : ℝ) := by - let f : ℝ → ℝ := fun t => 1 / (kB * t) - have h_eq : EqOn betaFromReal f (Set.Ioi 0) := beta_fun_T_eq_on_Ioi +lemma deriv_β_wrt_T (T : Temperature) (hT_pos : 0 < T.val) : + HasDerivWithinAt βFromReal (-1 / (kB * (T.val : ℝ)^2)) (Set.Ioi 0) (T.val : ℝ) := by + let f : ℝ → ℝ := fun t => (1 : ℝ) / (kB * t) + have h_eq : EqOn βFromReal f (Set.Ioi 0) := β_fun_T_eq_on_Ioi have hTne : (T.val : ℝ) ≠ 0 := ne_of_gt hT_pos have hf_def : f = fun t : ℝ => (kB)⁻¹ * t⁻¹ := by funext t @@ -329,27 +971,26 @@ lemma deriv_beta_wrt_T (T : Temperature) (hT_pos : 0 < T.val) : exact (h_deriv_f.hasDerivWithinAt).congr h_eq (h_eq h_mem) /-- Chain rule for β(T) : d/dT F(β(T)) = F'(β(T)) * (-1 / (kB * T^2)), within `Ioi 0`. -/ -lemma chain_rule_T_beta {F : ℝ → ℝ} {F' : ℝ} +lemma chain_rule_T_β {F : ℝ → ℝ} {F' : ℝ} (T : Temperature) (hT_pos : 0 < T.val) (hF_deriv : HasDerivWithinAt F F' (Set.Ioi 0) (T.β : ℝ)) : - HasDerivWithinAt (fun t : ℝ => F (betaFromReal t)) + HasDerivWithinAt (fun t : ℝ => F (βFromReal t)) (F' * (-1 / (kB * (T.val : ℝ)^2))) (Set.Ioi 0) (T.val : ℝ) := by - have hβ_deriv := deriv_beta_wrt_T (T:=T) hT_pos - have h_map : Set.MapsTo betaFromReal (Set.Ioi 0) (Set.Ioi 0) := by + have hβ_deriv := deriv_β_wrt_T (T:=T) hT_pos + have h_map : Set.MapsTo βFromReal (Set.Ioi 0) (Set.Ioi 0) := by intro t ht have ht_pos : 0 < t := ht - have : 0 < 1 / (kB * t) := by + have : 0 < (1 : ℝ) / (kB * t) := by have : 0 < kB * t := mul_pos kB_pos ht_pos exact one_div_pos.mpr this - have h_eqt : betaFromReal t = 1 / (kB * t) := beta_fun_T_eq_on_Ioi ht + have h_eqt : βFromReal t = (1 : ℝ) / (kB * t) := β_fun_T_eq_on_Ioi ht simpa [h_eqt] using this - have h_beta_at_T : betaFromReal (T.val : ℝ) = (T.β : ℝ) := by + have h_β_at_T : βFromReal (T.val : ℝ) = (T.β : ℝ) := by have hTposR : 0 < (T.val : ℝ) := hT_pos - have h_eqt := beta_fun_T_eq_on_Ioi hTposR + have h_eqt := β_fun_T_eq_on_Ioi hTposR simpa [Temperature.β, Temperature.toReal] using h_eqt - have hF_deriv' : HasDerivWithinAt F F' (Set.Ioi 0) (betaFromReal (T.val : ℝ)) := by - simpa [h_beta_at_T] using hF_deriv + have hF_deriv' : HasDerivWithinAt F F' (Set.Ioi 0) (βFromReal (T.val : ℝ)) := by + simpa [h_β_at_T] using hF_deriv have h_comp := hF_deriv'.comp (T.val : ℝ) hβ_deriv h_map simpa [mul_comm] using h_comp - end Temperature diff --git a/PhysLean/Thermodynamics/Temperature/TemperatureScales.lean b/PhysLean/Thermodynamics/Temperature/TemperatureScales.lean new file mode 100644 index 000000000..87403a336 --- /dev/null +++ b/PhysLean/Thermodynamics/Temperature/TemperatureScales.lean @@ -0,0 +1,241 @@ +/- +Copyright (c) 2026 Trong-Nghia Be. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Trong-Nghia Be, Tan-Phuoc-Hung Le +-/ +import PhysLean.Thermodynamics.Temperature.Basic +import PhysLean.Thermodynamics.Temperature.TemperatureUnits +/-! + +# Affine temperature scales === TODO TIL THE END OF THE FILE + +`Temperature` stores absolute temperature in kelvin (`ℝ≥0`), which is the physically meaningful quantity used by thermodynamics and statistical mechanics. + +This file introduces affine display scales (such as Celsius and Fahrenheit), where the reading is allowed to be negative while the corresponding absolute temperature remains nonnegative. + +-/ + +open NNReal + +/-- An affine scale for reading temperatures. + +- `unit` gives the size of one degree on this scale as a multiplicative temperature interval. +- `absoluteZero` is the reading on this scale corresponding to `0 K`. + For example, on the Celsius scale this is `-273.15`. +-/ +structure TemperatureScale where + /-- The multiplicative interval unit for one degree on this scale. -/ + unit : TemperatureUnit + /-- The reading corresponding to absolute zero (`0 K`). -/ + absoluteZero : ℝ + +namespace TemperatureScale + +/-- Convert a reading in an affine temperature scale into kelvin as a real number. + +- Input: + - `s` of type `TemperatureScale`: the affine temperature scale. + - `reading` of type `ℝ`: the reading on the affine scale. +- Output: + - result of type `ℝ`: the corresponding temperature in kelvin as a real number. + +- Algorithm: + 1. Subtract `s.absoluteZero` from `reading` to get the temperature interval above absolute zero. + 2. Multiply the result by the ratio of `s.unit` to `TemperatureUnit.kelvin` to convert the interval to kelvin. +-/ +noncomputable def toKelvinReal (s : TemperatureScale) (reading : ℝ) : ℝ := + (reading - s.absoluteZero) * (s.unit / TemperatureUnit.kelvin : ℝ) + +/-- Convert a kelvin value into a reading in an affine temperature scale as a real number. -/ +noncomputable def fromKelvinReal (s : TemperatureScale) (k : ℝ) : ℝ := + s.absoluteZero + k * (TemperatureUnit.kelvin / s.unit : ℝ) + +lemma fromKelvinReal_toKelvinReal (s : TemperatureScale) (reading : ℝ) : + fromKelvinReal s (toKelvinReal s reading) = reading := by + unfold fromKelvinReal toKelvinReal + have hmul : (s.unit / TemperatureUnit.kelvin : ℝ) * + (TemperatureUnit.kelvin / s.unit : ℝ) = 1 := by + calc + (s.unit / TemperatureUnit.kelvin : ℝ) * (TemperatureUnit.kelvin / s.unit : ℝ) + = (s.unit / s.unit : ℝ) := + TemperatureUnit.div_mul_div_coe s.unit TemperatureUnit.kelvin s.unit + _ = 1 := by simp + calc + s.absoluteZero + + ((reading - s.absoluteZero) * (s.unit / TemperatureUnit.kelvin : ℝ)) * + (TemperatureUnit.kelvin / s.unit : ℝ) + = s.absoluteZero + + (reading - s.absoluteZero) * + ((s.unit / TemperatureUnit.kelvin : ℝ) * + (TemperatureUnit.kelvin / s.unit : ℝ)) := by ring + _ = s.absoluteZero + (reading - s.absoluteZero) * 1 := by rw [hmul] + _ = reading := by ring + +lemma toKelvinReal_fromKelvinReal (s : TemperatureScale) (k : ℝ) : + toKelvinReal s (fromKelvinReal s k) = k := by + unfold fromKelvinReal toKelvinReal + have hmul : (TemperatureUnit.kelvin / s.unit : ℝ) * + (s.unit / TemperatureUnit.kelvin : ℝ) = 1 := by + calc + (TemperatureUnit.kelvin / s.unit : ℝ) * (s.unit / TemperatureUnit.kelvin : ℝ) + = (TemperatureUnit.kelvin / TemperatureUnit.kelvin : ℝ) := + TemperatureUnit.div_mul_div_coe TemperatureUnit.kelvin s.unit TemperatureUnit.kelvin + _ = 1 := by simp + calc + (s.absoluteZero + k * (TemperatureUnit.kelvin / s.unit : ℝ) - s.absoluteZero) * + (s.unit / TemperatureUnit.kelvin : ℝ) + = (k * (TemperatureUnit.kelvin / s.unit : ℝ)) * + (s.unit / TemperatureUnit.kelvin : ℝ) := by ring + _ = k * ((TemperatureUnit.kelvin / s.unit : ℝ) * + (s.unit / TemperatureUnit.kelvin : ℝ)) := by ring + _ = k * 1 := by rw [hmul] + _ = k := by ring + +/-- Kelvin scale. -/ +def kelvin : TemperatureScale := ⟨TemperatureUnit.kelvin, 0⟩ + +/-- Celsius scale. -/ +noncomputable def celsius : TemperatureScale := ⟨TemperatureUnit.kelvin, -(27315 : ℝ) / 100⟩ + +/-- Rankine scale. -/ +noncomputable def rankine : TemperatureScale := ⟨TemperatureUnit.rankine, 0⟩ + +/-- Fahrenheit scale. -/ +noncomputable def fahrenheit : TemperatureScale := ⟨TemperatureUnit.rankine, -(45967 : ℝ) / 100⟩ + +@[simp] +lemma toKelvinReal_kelvin (k : ℝ) : toKelvinReal kelvin k = k := by + simp [toKelvinReal, kelvin] + +@[simp] +lemma fromKelvinReal_kelvin (k : ℝ) : fromKelvinReal kelvin k = k := by + simp [fromKelvinReal, kelvin] + +@[simp] +lemma toKelvinReal_celsius (c : ℝ) : + toKelvinReal celsius c = c + (27315 : ℝ) / 100 := by + calc + toKelvinReal celsius c + = (c - (-(27315 : ℝ) / 100)) * (TemperatureUnit.kelvin / TemperatureUnit.kelvin : ℝ) := by + rfl + _ = c - (-(27315 : ℝ) / 100) := by simp + _ = c + (27315 : ℝ) / 100 := by ring + +@[simp] +lemma fromKelvinReal_celsius (k : ℝ) : + fromKelvinReal celsius k = -(27315 : ℝ) / 100 + k := by + simp [fromKelvinReal, celsius, add_comm] + +@[simp] +lemma toKelvinReal_fahrenheit (f : ℝ) : + toKelvinReal fahrenheit f = (f + (45967 : ℝ) / 100) * (5 / 9 : ℝ) := by + calc + toKelvinReal fahrenheit f + = (f - (-(45967 : ℝ) / 100)) * (TemperatureUnit.rankine / TemperatureUnit.kelvin : ℝ) := by + rfl + _ = (f + (45967 : ℝ) / 100) * (5 / 9 : ℝ) := by + have hneg : f - (-(45967 : ℝ) / 100) = f + (45967 : ℝ) / 100 := by ring + rw [hneg] + simp [TemperatureUnit.rankine, TemperatureUnit.scale_div_self] + +@[simp] +lemma fromKelvinReal_fahrenheit (k : ℝ) : + fromKelvinReal fahrenheit k = -(45967 : ℝ) / 100 + k * (9 / 5 : ℝ) := by + simp [fromKelvinReal, fahrenheit, TemperatureUnit.rankine, TemperatureUnit.self_div_scale, + add_comm] + +lemma zero_le_toKelvinReal_celsius_iff (c : ℝ) : + 0 ≤ toKelvinReal celsius c ↔ (-(27315 : ℝ) / 100) ≤ c := by + rw [toKelvinReal_celsius] + constructor <;> intro h <;> linarith + +lemma zero_le_toKelvinReal_fahrenheit_iff (f : ℝ) : + 0 ≤ toKelvinReal fahrenheit f ↔ (-(45967 : ℝ) / 100) ≤ f := by + rw [toKelvinReal_fahrenheit] + constructor + · intro h + have h' : 0 ≤ f + (45967 : ℝ) / 100 := + (mul_nonneg_iff_of_pos_right (show (0 : ℝ) < 5 / 9 by norm_num)).1 h + linarith + · intro h + have h' : 0 ≤ f + (45967 : ℝ) / 100 := by linarith + exact mul_nonneg h' (by norm_num) + +end TemperatureScale + +namespace Temperature + +/-- Convert an absolute temperature to a reading in an affine scale. -/ +noncomputable def toScale (T : Temperature) (s : TemperatureScale) : ℝ := + TemperatureScale.fromKelvinReal s (T : ℝ) + +/-- Build an absolute temperature from an affine scale reading and a proof it is physically valid. -/ +noncomputable def ofScale (s : TemperatureScale) (x : ℝ) + (hx : 0 ≤ TemperatureScale.toKelvinReal s x) : Temperature := + Temperature.ofRealNonneg (TemperatureScale.toKelvinReal s x) hx + +/-- Build an absolute temperature from an affine scale reading, failing below absolute zero. -/ +noncomputable def ofScale? (s : TemperatureScale) (x : ℝ) : Option Temperature := + if hx : 0 ≤ TemperatureScale.toKelvinReal s x then some (ofScale s x hx) else none + +/-- Convert an absolute temperature to Celsius. -/ +noncomputable def toCelsius (T : Temperature) : ℝ := + toScale T TemperatureScale.celsius + +/-- Convert an absolute temperature to Fahrenheit. -/ +noncomputable def toFahrenheit (T : Temperature) : ℝ := + toScale T TemperatureScale.fahrenheit + +/-- Build an absolute temperature from Celsius. -/ +noncomputable def ofCelsius (c : ℝ) (hc : (-(27315 : ℝ) / 100) ≤ c) : Temperature := + ofScale TemperatureScale.celsius c ((TemperatureScale.zero_le_toKelvinReal_celsius_iff c).2 hc) + +/-- Build an absolute temperature from Fahrenheit. -/ +noncomputable def ofFahrenheit (f : ℝ) (hf : (-(45967 : ℝ) / 100) ≤ f) : Temperature := + ofScale TemperatureScale.fahrenheit f + ((TemperatureScale.zero_le_toKelvinReal_fahrenheit_iff f).2 hf) + +/-- Build an absolute temperature from Celsius, returning `none` below absolute zero. -/ +noncomputable def ofCelsius? (c : ℝ) : Option Temperature := + ofScale? TemperatureScale.celsius c + +/-- Build an absolute temperature from Fahrenheit, returning `none` below absolute zero. -/ +noncomputable def ofFahrenheit? (f : ℝ) : Option Temperature := + ofScale? TemperatureScale.fahrenheit f + +lemma toScale_ofScale (s : TemperatureScale) (x : ℝ) + (hx : 0 ≤ TemperatureScale.toKelvinReal s x) : + toScale (ofScale s x hx) s = x := by + simp [toScale, ofScale, Temperature.ofRealNonneg, Temperature.ofNNReal, + Temperature.toReal, TemperatureScale.fromKelvinReal_toKelvinReal] + +@[simp] +lemma toCelsius_zero : toCelsius (0 : Temperature) = (-(27315 : ℝ) / 100) := by + change TemperatureScale.fromKelvinReal TemperatureScale.celsius (((0 : Temperature).val : ℝ)) = + (-(27315 : ℝ) / 100) + have hzero : (((0 : Temperature).val : ℝ)) = 0 := by rfl + simp [hzero, TemperatureScale.fromKelvinReal, TemperatureScale.celsius] + +@[simp] +lemma toFahrenheit_zero : toFahrenheit (0 : Temperature) = (-(45967 : ℝ) / 100) := by + change TemperatureScale.fromKelvinReal TemperatureScale.fahrenheit (((0 : Temperature).val : ℝ)) = + (-(45967 : ℝ) / 100) + have hzero : (((0 : Temperature).val : ℝ)) = 0 := by rfl + simp [hzero, TemperatureScale.fromKelvinReal, TemperatureScale.fahrenheit] + +@[simp] +lemma ofCelsius?_below_absoluteZero : ofCelsius? ((-(27315 : ℝ) / 100) - 1) = none := by + simp [ofCelsius?, ofScale?] + linarith + +@[simp] +lemma ofFahrenheit?_below_absoluteZero : ofFahrenheit? ((-(45967 : ℝ) / 100) - 1) = none := by + simp [ofFahrenheit?, ofScale?] + linarith + +lemma minusForty_celsius_eq_minusForty_fahrenheit : + toFahrenheit (ofCelsius (-40) (by norm_num)) = (-40 : ℝ) := by + simp [toFahrenheit, toScale, ofCelsius, ofScale] + norm_num + +end Temperature diff --git a/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean b/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean index cff880aba..9d48a772c 100644 --- a/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean +++ b/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean @@ -1,22 +1,22 @@ /- Copyright (c) 2025 Joseph Tooby-Smith. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. -Authors: Joseph Tooby-Smith +Authors: Trong-Nghia Be, Tan-Phuoc-Hung Le, Joseph Tooby-Smith -/ import Mathlib.Geometry.Manifold.Diffeomorph import PhysLean.SpaceAndTime.Time.Basic /-! -# Units on Temperature +# Units on Temperature === TODO TIL THE END OF THE FILE -A unit of temperature corresponds to a choice of translationally-invariant +A unit of temperature interval corresponds to a choice of translationally-invariant metric on the temperature manifold (to be defined diffeomorphic to `ℝ≥0`). Such a choice is (non-canonically) equivalent to a choice of positive real number. We define the type `TemperatureUnit` to be equivalent to the positive reals. On `TemperatureUnit` there is an instance of division giving a real number, corresponding to the -ratio of the two scales of temperature unit. +ratio of the two interval scales. To define specific temperature units, we first state the existence of a a given temperature unit, and then construct all other temperature units from it. @@ -28,7 +28,7 @@ existence of the temperature unit of kelvin, and construct all other temperature open NNReal /-- The choices of translationally-invariant metrics on the temperature-manifold. - Such a choice corresponds to a choice of units for temperature. -/ + Such a choice corresponds to a multiplicative choice of unit scale for temperature intervals. -/ structure TemperatureUnit where /-- The underlying scale of the unit. -/ val : ℝ @@ -150,8 +150,7 @@ noncomputable def microkelvin : TemperatureUnit := scale (1e-6) kelvin /-- The temperature unit of degrees millikelvin (10^(-3) kelvin). -/ noncomputable def millikelvin : TemperatureUnit := scale (1e-3) kelvin -/-- The temperature unit of degrees fahrenheit ((5/9) of a kelvin). - Note, this is fahrenheit starting at `0` absolute temperature. -/ -noncomputable def absoluteFahrenheit : TemperatureUnit := scale (5 / 9) kelvin +/-- The temperature unit of degrees rankine ((5/9) of a kelvin). -/ +noncomputable def rankine : TemperatureUnit := scale (5 / 9) kelvin end TemperatureUnit From f206334da8fdea2c5d42b472219319f75f704f28 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 00:24:21 +0700 Subject: [PATCH 02/12] docs(thermodynamics): offload from lemmas/definitions docstrings to line comments TODO: from `tendsto_const_inv_mul_bound_pos` downwards --- .../Thermodynamics/Temperature/Basic.lean | 528 +++++++----------- 1 file changed, 208 insertions(+), 320 deletions(-) diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index d7c5b7120..462b53010 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -307,514 +307,402 @@ lemma β_pos (T : Temperature) (h_T_pos : 0 < T.val) : 0 < (T.β : ℝ) := by open Filter Topology -/-- Helper lemma: The denominator `kB * b` used in `ofβ` is nonnegative. +/-- Helper lemma for `Temperature`: -- Premises: - - `b` of type `ℝ≥0`: The inverse temperature input. - -- Conclusion: - - The conclusion is `0 ≤ kB * (b : ℝ)`: The denominator in the formula for `ofβ` is nonnegative. - -- Proof: - - We apply `mul_nonneg` to the product `kB * (b : ℝ)`. - - The first factor is nonnegative by `kB_nonneg`. - - The second factor is nonnegative because `b : ℝ≥0` carries the proof `b.property : 0 ≤ (b : ℝ)`. QED. +The denominator of `ofβ` is nonnegative. -/ private lemma ofβ_den_nonneg (b : ℝ≥0) : 0 ≤ kB * (b : ℝ) := by + -- We apply `mul_nonneg` to show that the product `kB * (b : ℝ)` is nonnegative by showing that + -- both factors are nonnegative. apply mul_nonneg + -- `case ha`: The goal is `⊢ 0 ≤ kB`, which is true by the lemma `kB_nonneg`, since the Boltzmann + -- constant is a positive physical constant. QED for this case. · exact kB_nonneg + -- `case hb`: The goal is `⊢ 0 ≤ (b : ℝ)`, which is true by the fact that `b` of type `ℝ≥0` + -- carries the proof `b.property : 0 ≤ (b : ℝ)`. QED for this case. · exact b.property + -- All cases have been proven. QED. -/-- Helper lemma: The real-valued expression `1 / (kB * b)` is nonnegative. - -- Premises: - - `b` of type `ℝ≥0`: The inverse temperature input. +/-- Helper lemma for `Temperature`: -- Conclusion: - - The conclusion is `0 ≤ (1 : ℝ) / (kB * (b : ℝ))`: The real-valued formula used by `ofβ` is nonnegative. - -- Proof: - - We apply `div_nonneg`. - - The numerator is nonnegative by `zero_le_one`. - - The denominator is nonnegative by `ofβ_den_nonneg b`. QED. +The real-valued expression `1 / (kB * b)` is nonnegative. -/ private lemma ofβ_real_nonneg (b : ℝ≥0) : 0 ≤ (1 : ℝ) / (kB * (b : ℝ)) := by + -- We apply `div_nonneg` to show that the fraction `1 / (kB * b)` is nonnegative by showing that + -- both the numerator and the denominator are nonnegative. apply div_nonneg + -- `case ha`: The goal is `⊢ 0 ≤ 1`, which is true by the lemma `zero_le_one`. QED for this case. · exact zero_le_one + -- `case hb`: The goal is `⊢ 0 ≤ kB * (b : ℝ)`, which is true by the lemma `ofβ_den_nonneg b`. + -- QED for this case. · exact ofβ_den_nonneg b + -- All cases have been proven. QED. -/-- Helper lemma: Continuity at a positive point for the real formula `(t : ℝ) ↦ (1 : ℝ) / (kB * t)`. - -- Premises: - - `x` of type `ℝ≥0`: The point where continuity is evaluated. - - `h_x_pos : 0 < x`: A proof that `x` is strictly positive. +/-- Helper lemma for `Temperature`: -- Conclusion: - - The conclusion is `ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ)`. - -- Proof: - - We refine the goal using `ContinuousAt.div₀`, which requires us to prove continuity of the numerator and denominator separately: - - Case refine_1: `⊢ ContinuousAt (fun t => 1) ↑x`. - - This is true because constant functions are continuous everywhere. We use `fun_prop` to establish this. - - Case refine_2: `⊢ ContinuousAt (HMul.hMul kB) ↑x`. - - This is true because multiplication by a constant is continuous everywhere. We use `fun_prop` to establish this. - - Case refine_3: `⊢ kB * ↑x ≠ 0`. - - We have the hypothesis `h_x_ne_zero : (x : ℝ) ≠ 0` derived from `ne_of_gt h_x_pos`; which means: "Given a and b, if a > b, then a ≠ b" - and since we have `0 < x`, we conclude `x ≠ 0`. - - We then use `mul_ne_zero kB_ne_zero h_x_ne_zero` to conclude that the product `kB * (x : ℝ)` is nonzero, since both factors are nonzero. QED. --/ -private lemma ofβ_realExpr_continuousAt_real (x : ℝ≥0) (h_x_pos : 0 < x) : ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ) := by +Continuity at a positive point for the real formula `(t : ℝ) ↦ (1 : ℝ) / (kB * t)`. +-/ +private lemma ofβ_realExpr_continuousAt_real (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ) := by + -- We refine the goal using `ContinuousAt.div₀`, which requires us to prove continuity of the + -- numerator and denominator separately: refine ContinuousAt.div₀ ?_ ?_ ?_ + -- `case refine_1`: The goal is `⊢ ContinuousAt (fun t => 1) ↑x`. + -- This is true because constant functions are continuous everywhere. We use `fun_prop` to + -- establish this. · fun_prop + -- `case refine_2`: The goal is `⊢ ContinuousAt (HMul.hMul kB) ↑x`. + -- This is true because multiplication by a constant is continuous everywhere. + -- We use `fun_prop` to establish this. · fun_prop + -- `case refine_3`: The goal is `⊢ kB * ↑x ≠ 0`. + -- We have the hypothesis `h_x_ne_zero : (x : ℝ) ≠ 0` derived from `ne_of_gt h_x_pos`; + -- which means: "Given a and b, if a > b, then a ≠ b" - and since we have `0 < x`, + -- we conclude `x ≠ 0`. · have h_x_ne_zero : (x : ℝ) ≠ 0 := by exact (ne_of_gt h_x_pos) exact mul_ne_zero kB_ne_zero h_x_ne_zero -/-- Helper lemma: Continuity at a positive point for the same formula on `ℝ≥0`. - -- Premises: - - `x` of type `ℝ≥0`: The point where continuity is evaluated. - - `h_x_pos : 0 < x`: A proof that `x` is strictly positive. - -- Conclusion: - - The conclusion is `ContinuousAt (fun (b : ℝ≥0) => (1 : ℝ) / (kB * (b : ℝ))) x`. +/-- Helper lemma for `Temperature`: -- Proof: - - Call the function to be proved continuous `f : ℝ≥0 → ℝ` defined by `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`. - - This is the same as the function in the goal, but we give it a name for clarity. - - We define `g : ℝ → ℝ` as `g (t : ℝ) := (1 : ℝ) / (kB * t)`, which is the same formula but defined on `ℝ`. - - We define `h : ℝ≥0 → ℝ` as `h (b : ℝ≥0) := (b : ℝ)`, which is the coercion from `ℝ≥0` to `ℝ`. - - We then prove that `f = g ∘ h` by simplifying both sides and showing they are equal. - - This is done by `rfl`, since both sides are definitionally equal. - - We then prove that `g` is continuous at `x : ℝ` using the previous lemma `ofβ_realExpr_continuousAt_real x h_x_pos`, resulting in the hypothesis `h_continuousAt_real`. - - We also prove that `h` is continuous at `x : ℝ≥0` using `continuous_subtype_val.continuousAt`, which states that the coercion from a subtype to its parent type is continuous at every point, resulting in the hypothesis `h_continuousAt_subtype`. - - Finally, we conclude that `f` is continuous at `x` by using the composition of continuous functions: `h_continuousAt_real.comp h_continuousAt_subtype`. QED. --/ -private lemma ofβ_realExpr_continuousAt_nnreal (x : ℝ≥0) (h_x_pos : 0 < x): ContinuousAt (fun (b : ℝ≥0) => (1 : ℝ) / (kB * b)) x := by +Continuity at a positive point for the same formula on `ℝ≥0`. +-/ +private lemma ofβ_realExpr_continuousAt_nnreal (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (fun (b : ℝ≥0) => (1 : ℝ) / (kB * b)) x := by + -- We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`. + -- This is the same as the function in the goal, but we give it a name for clarity. let f : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (1 : ℝ) / (kB * b) + -- We define `g : ℝ → ℝ` as `g (t : ℝ) := (1 : ℝ) / (kB * t)`. + -- This is the same formula as `f`, but defined on `ℝ`. let g : ℝ → ℝ := fun (t : ℝ) => (1 : ℝ) / (kB * t) + -- We define `h : ℝ≥0 → ℝ` as `h (b : ℝ≥0) := (b : ℝ)`. + -- This is the coercion from `ℝ≥0` to `ℝ`. let h : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (b : ℝ) + -- We then prove that `f = g ∘ h` by simplifying both sides and showing they are equal. + -- This is done by `rfl`, since both sides are definitionally equal. have f_eq_g_comp_h : f = (g ∘ h) := by rfl + -- We then prove that `g` is continuous at `x : ℝ` using the previous lemma `ofβ_realExpr_continuousAt_real x h_x_pos`, resulting in the hypothesis `h_continuousAt_real`. have h_continuousAt_real : ContinuousAt g (x : ℝ) := ofβ_realExpr_continuousAt_real x h_x_pos + -- We also prove that `h` is continuous at `x : ℝ≥0` using `continuous_subtype_val.continuousAt`, + -- which states that the coercion from a subtype to its parent type is continuous at every point, + -- resulting in the hypothesis `h_continuousAt_subtype`. have h_continuousAt_subtype : ContinuousAt h (x : ℝ≥0) := continuous_subtype_val.continuousAt + -- Finally, we conclude that `f` is continuous at `x` by using the composition of + -- continuous functions: `h_continuousAt_real.comp h_continuousAt_subtype`. QED. exact h_continuousAt_real.comp h_continuousAt_subtype -/-- Helper lemma: Continuity at a positive point for the `ℝ≥0`-valued `val` component of `ofβ`. +/-- Helper lemma for `Temperature`: -- Premises: - - `x` of type `ℝ≥0`: The point where continuity is evaluated. - - `h_x_pos : 0 < x`: A proof that `x` is strictly positive. - -- Conclusion: - - The conclusion is `ContinuousAt (fun (b : ℝ≥0) => ((ofβ b).val : ℝ≥0)) x`. - -- Proof: - - We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`, which is the real-valued formula used by `ofβ`. - - Then, we prove that `f` is continuous at `x` using the previous lemma `ofβ_realExpr_continuousAt_nnreal x h_x_pos`, resulting in the hypothesis `h_f_continuousAt`. - - Next, we prove that `f` is nonnegative for all `b : ℝ≥0` using the lemma `ofβ_real_nonneg b`, resulting in the hypothesis `h_f_nonneg`. - - We then define `g : ℝ≥0 → ℝ≥0` as `g (b : ℝ≥0) := ⟨f b, h_f_nonneg b⟩`, which is the same formula as `f` but with codomain restricted to `ℝ≥0`. - - We prove that `g` is continuous at `x` by using the fact that if a real-valued function is continuous, then its codomain-restricted version is also continuous. This gives us the hypothesis `h_g_continuousAt`. - - Finally, we conclude that the `val` component of `ofβ` is continuous at `x` by using the hypothesis `h_g_continuousAt`, since `g` is definitionally equal to the function we want to prove continuous. QED. --/ -private lemma ofβ_val_continuousAt (x : ℝ≥0) (h_x_pos : 0 < x) : ContinuousAt (fun (b : ℝ≥0) => ((ofβ b).val : ℝ≥0)) x := by +Continuity at a positive point for the `ℝ≥0`-valued `val` component of `ofβ`. +-/ +private lemma ofβ_val_continuousAt (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (fun (b : ℝ≥0) => ((ofβ b).val : ℝ≥0)) x := by + -- We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`, + -- which is the real-valued formula used by `ofβ`. let f : ℝ≥0 → ℝ := fun b => (1 : ℝ) / (kB * b) + -- Then, we prove that `f` is continuous at `x` using the previous lemma + -- `ofβ_realExpr_continuousAt_nnreal x h_x_pos`, + -- resulting in the hypothesis `h_f_continuousAt`. have h_continuousAt_nnreal : ContinuousAt f x := by exact ofβ_realExpr_continuousAt_nnreal x h_x_pos + -- Next, we prove that `f` is nonnegative for all `b : ℝ≥0` using the lemma `ofβ_real_nonneg b`, + -- resulting in the hypothesis `h_f_nonneg`. have h_f_nonneg : ∀ b : ℝ≥0, 0 ≤ f (b : ℝ≥0) := by intro b exact ofβ_real_nonneg b + -- We then define `g : ℝ≥0 → ℝ≥0` as `g (b : ℝ≥0) := ⟨f b, h_f_nonneg b⟩`, + -- which is the same formula as `f` but with codomain restricted to `ℝ≥0`. let g : ℝ≥0 → ℝ≥0 := fun b => (⟨f b, h_f_nonneg b⟩ : ℝ≥0) + -- We prove that `g` is continuous at `x` by using the fact that if a real-valued function + -- is continuous, then its codomain-restricted version is also continuous. + -- This gives us the hypothesis `h_g_continuousAt`. have h_g_continuousAt : ContinuousAt g x := by exact h_continuousAt_nnreal.codRestrict h_f_nonneg + -- Finally, we conclude that the `val` component of `ofβ` is continuous at `x` + -- by using the hypothesis `h_g_continuousAt`, + -- since `g` is definitionally equal to the function we want to prove continuous. QED. exact h_g_continuousAt -/-- Helper lemma: the topology on `Temperature` is induced by the coercion to `ℝ≥0`. - -- Premises: - - None. - -- Conclusion: - - The conclusion is `Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0))`. +/-- Helper lemma for `Temperature`: -- Proof: - - This is immediate from the topology instance definition, which is exactly `induced` by this coercion map. Therefore the witness is `⟨rfl⟩`. QED. +The topology on `Temperature` is induced by the coercion to `ℝ≥0`. -/ -private lemma temperature_val_isInducing : Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0)) := by +private lemma temperature_val_isInducing : + Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0)) := by + -- This is immediate from the topology instance definition, + -- which is exactly `induced` by this coercion map. + -- Therefore the witness is `⟨rfl⟩`. exact ⟨rfl⟩ -/-- Helper lemma: continuity of `ofβ` at every strictly positive input. - -- Premises: - - `x` of type `ℝ≥0`: The point where continuity is evaluated. - - `h_x_pos : 0 < x`: A proof that the point is strictly positive. - -- Conclusion: - - The conclusion is `ContinuousAt (ofβ : ℝ≥0 → Temperature) x`. +/-- Helper lemma for `Temperature`: -- Proof: - - We refine the goal using `temperature_val_isInducing.continuousAt_iff`, which states that continuity of a function into `Temperature` can be checked by continuity of its composition with the coercion to `ℝ≥0`. - - The goal is now `⊢ ContinuousAt ((fun T => T.val) ∘ ofβ) x`. - - This is exactly the content of the previous lemma `ofβ_val_continuousAt x h_x_pos`, so we apply that to conclude. QED. +Continuity of `ofβ` at every strictly positive input. -/ -private lemma ofβ_continuousAt_of_pos (x : ℝ≥0) (h_x_pos : 0 < x) : ContinuousAt (ofβ : ℝ≥0 → Temperature) x := by +private lemma ofβ_continuousAt_of_pos (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (ofβ : ℝ≥0 → Temperature) x := by + -- We refine the goal using `temperature_val_isInducing.continuousAt_iff`, + -- which states that continuity of a function into `Temperature` can be checked + -- by continuity of its composition with the coercion to `ℝ≥0`. + -- The goal is now `⊢ ContinuousAt ((fun T => T.val) ∘ ofβ) x`. refine (temperature_val_isInducing.continuousAt_iff).mpr ?_ + -- This is exactly the content of the previous lemma `ofβ_val_continuousAt x h_x_pos`, + -- so we apply that to conclude. QED. exact ofβ_val_continuousAt x h_x_pos -/-- Lemma: The function `ofβ` is continuous on the interval `(0, ∞)`. - -- Premises: - - None. - -- Conclusion: - - The conclusion is `ContinuousOn (ofβ : ℝ≥0 → Temperature) (Set.Ioi 0)`. +/-- Lemma for `Temperature`: -- Proof: - - We refine the goal using `continuousOn_of_forall_continuousAt`, which reduces continuity on a set to continuity at every point in that set. - - The goal is now `⊢ ∀ x ∈ Set.Ioi 0, ContinuousAt ofβ x`. - - We introduce `x : ℝ≥0` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. - - From `h_x_in_set`, we derive `h_x_pos : 0 < x` by: - - Simplifying the definition of `Set.Ioi 0`, which states that `x ∈ Set.Ioi 0` means `0 < x`. - - Extracting the strict inequality `0 < x` from this definition. - - Given `x : ℝ≥0` and `h_x_pos : 0 < x`, we can prove the goal with `ofβ_continuousAt_of_pos x h_x_pos`. QED. +The function `ofβ` is continuous on the interval `(0, ∞)`. -/ lemma ofβ_continuousOn : ContinuousOn (ofβ : ℝ≥0 → Temperature) (Set.Ioi 0) := by + -- We refine the goal using `continuousOn_of_forall_continuousAt`, + -- which reduces continuity on a set to continuity at every point in that set. + -- The goal is now `⊢ ∀ x ∈ Set.Ioi 0, ContinuousAt ofβ x`. refine continuousOn_of_forall_continuousAt ?_ + -- We introduce `x : ℝ≥0` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. intro x h_x_in_set + -- From `h_x_in_set`, we derive `h_x_pos : 0 < x` by: have h_x_pos : 0 < x := by + -- Simplifying the definition of `Set.Ioi 0`, which states that `x ∈ Set.Ioi 0` means `0 < x`. simp at h_x_in_set + -- Extracting the strict inequality `0 < x` from this definition. exact h_x_in_set + -- Given `x : ℝ≥0` and `h_x_pos : 0 < x`, + -- we can prove the goal with `ofβ_continuousAt_of_pos x h_x_pos`. QED. exact ofβ_continuousAt_of_pos x h_x_pos -/-- Lemma: The function `ofβ` is differentiable on the interval `(0, ∞)`. - -- Premises: - - None. - -- Conclusion: - - The conclusion is `DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0)`: The function mapping `x` to the real-valued `val` component of `ofβ (Real.toNNReal x)` is differentiable on the interval `(0, ∞)`. +/-- Lemma for `Temperature`: -- Proof: - - We refine the goal using `DifferentiableOn.congr`, which allows us to prove differentiability by showing that the function is equal to a simpler function that we can easily differentiate. We now have two cases: - - Case refine_1: `⊢ DifferentiableOn ℝ (fun x => 1 / (kB * x)) (Set.Ioi 0)`. - - We further refine this using `DifferentiableOn.fun_div`, which requires us to prove differentiability of the numerator and denominator separately, and that the denominator is nonzero on the set: - - Case refine_1.refine_1: `⊢ DifferentiableOn ℝ (fun x => 1) (Set.Ioi 0)`. - - This is true because constant functions are differentiable everywhere. We use `fun_prop` to establish this. - - Case refine_1.refine_2: `⊢ DifferentiableOn ℝ (HMul.hMul kB) (Set.Ioi 0)`. - - This is true because multiplication by a constant is differentiable everywhere. We use `fun_prop` to establish this. - - Case refine_1.refine_3: `⊢ ∀ x ∈ Set.Ioi 0, kB * x ≠ 0`. - - We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. The goal is now `⊢ kB * x ≠ 0`. - - We derive `h_x_ne_zero : x ≠ 0` from `h_x_in_set` by noting that if `x` is strictly greater than `0`, then it cannot be equal to `0`. - - We then apply `mul_ne_zero` to conclude that `kB * x` is nonzero. - - The first factor `kB` is nonzero by `kB_ne_zero`. - - The second factor `x` is nonzero by `h_x_ne_zero`. - - This completes the proof of this case. - - Case refine_2: `⊢ ∀ x ∈ Set.Ioi 0, ↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. - - We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. The goal is now `↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. - - We derive `h_x_pos : 0 < x` from `h_x_in_set` by simplifying the definition of `Set.Ioi 0` to extract the strict inequality `0 < x`. - - We also derive `h_x_nonneg : 0 ≤ x` from `h_x_pos` by noting that if `x` is strictly greater than `0`, then it can be considered as "greater than or equal to `0`" as well (since `0 < x` implies `0 ≤ x`). - - We then simplify the goal using `simp` to get a new goal that is a disjunction: `⊢ 0 ≤ x ∨ kB = 0`. - - We only have to prove the left disjunct `0 ≤ x` since `kB` is nonzero by `kB_ne_zero` (thus the right disjunct is false). - - We have already established `h_x_nonneg : 0 ≤ x`, so we can conclude this case by left disjunction and using `h_x_nonneg`. - - This completes the proof of this case. - - With both cases proved, we conclude that the original function is differentiable on the interval `(0, ∞)`. QED. --/ -lemma ofβ_differentiableOn : DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0) := by +The function `ofβ` is differentiable on the interval `(0, ∞)`. +-/ +lemma ofβ_differentiableOn : + DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0) := by + -- We refine the goal using `DifferentiableOn.congr`, which allows us to prove differentiability + -- by showing that the function is equal to a simpler function that we can easily differentiate. + -- We now have two cases: refine DifferentiableOn.congr (f := fun (x : ℝ) => (1 : ℝ) / (kB * x)) ?_ ?_ + -- `case refine_1` : The goal is `⊢ DifferentiableOn ℝ (fun x => 1 / (kB * x)) (Set.Ioi 0)`. + -- We further refine this using `DifferentiableOn.fun_div`, which requires us + -- to prove differentiability of the numerator and denominator separately, + -- and that the denominator is nonzero on the set: · refine DifferentiableOn.fun_div ?_ ?_ ?_ + -- `case refine_1.refine_1` : The goal is `⊢ DifferentiableOn ℝ (fun x => 1) (Set.Ioi 0)`. + -- This is true because constant functions are differentiable everywhere. + -- We use `fun_prop` to establish this. · fun_prop + -- `case refine_1.refine_2` : The goal is `⊢ DifferentiableOn ℝ (HMul.hMul kB) (Set.Ioi 0)`. + -- This is true because multiplication by a constant is differentiable everywhere. + -- We use `fun_prop` to establish this. · fun_prop + -- `case refine_1.refine_3` : The goal is `⊢ ∀ x ∈ Set.Ioi 0, kB * x ≠ 0`. + -- We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. + -- The goal is now `⊢ kB * x ≠ 0`. · intro x h_x_in_set + -- We derive `h_x_ne_zero : x ≠ 0` from `h_x_in_set` by noting that + -- if `x` is strictly greater than `0`, then it cannot be equal to `0`. have h_x_ne_zero : x ≠ 0 := by exact ne_of_gt h_x_in_set + -- We then apply `mul_ne_zero` to conclude that `kB * x` is nonzero. apply mul_ne_zero + -- The first factor `kB` is nonzero by `kB_ne_zero`. · exact kB_ne_zero + -- The second factor `x` is nonzero by `h_x_ne_zero`. + -- This completes the proof of this case. QED for `refine_1.refine_3`. + -- QED for `refine_1`. · exact h_x_ne_zero + -- `case refine_2` : The goal is + -- `⊢ ∀ x ∈ Set.Ioi 0, ↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. + -- We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. + -- The goal is now `↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. · intro x h_x_in_set + -- We derive `h_x_pos : 0 < x` from `h_x_in_set` by simplifying the definition of `Set.Ioi 0` + -- to extract the strict inequality `0 < x`. have h_x_pos : 0 < x := by simp at h_x_in_set exact h_x_in_set + -- We also derive `h_x_nonneg : 0 ≤ x` from `h_x_pos` by noting that + -- if `x` is strictly greater than `0`, then it can be considered as + -- "greater than or equal to `0`" as well (since `0 < x` implies `0 ≤ x`). have h_x_nonneg : 0 ≤ x := by simpa using h_x_pos.le + -- We then simplify the goal using `simp` to get a new goal + -- that is a disjunction: `⊢ 0 ≤ x ∨ kB = 0`. simp + -- We only have to prove the left disjunct `0 ≤ x` since `kB` is nonzero by `kB_ne_zero` + -- (thus the right disjunct is false). left + -- We have already established `h_x_nonneg : 0 ≤ x`, so we can conclude this case + -- by left disjunction and using `h_x_nonneg`. + -- This completes the proof of this case. QED for `refine_2`. + -- All cases have been proven. QED. simp [h_x_nonneg] /-! ### Convergence -/ open Filter Topology -/-- Lemma: The function `ofβ` produces strictly positive real-valued temperatures for sufficiently large inverse temperature β. - -- Premises: - - None. - -- Conclusion: - - The conclusion is `∀ᶠ b : ℝ≥0 in atTop, ((Temperature.ofβ b : Temperature) : ℝ) > 0`: For sufficiently large values of the inverse temperature `b`, the real-valued representation of the temperature `ofβ b` is strictly positive. +/-- Lemma for `Temperature`: -- Proof: - - We start by proving that for sufficiently large `b : ℝ≥0`, we have `1 ≤ b` using `Filter.eventually_ge_atTop 1`, which states that eventually, all elements of the filter at infinity are greater than or equal to `1`. This gives us the hypothesis `h_eventually_b_ge_one`. - - We then refine the goal using `h_eventually_b_ge_one.mono`, which allows us to prove the desired property for all `b` that satisfy `1 ≤ b`. The new goal is now `⊢ ∀ (x : ℝ≥0), 1 ≤ x → (ofβ x).toReal > 0`. - - We introduce `b : ℝ≥0` and the hypothesis `h_b_ge_one : 1 ≤ b` from the goal. The goal is now `⊢ (ofβ b).toReal > 0`. - - The goal is now `⊢ (1 : ℝ) / (kB * (↑b : ℝ)) > 0`. - - We derive `h_b_pos : 0 < (b : ℝ)` using `zero_lt_one.trans_le h_b_ge_one`, which states that if `0 < 1` and `1 ≤ b`, then `0 < b`. - - We derive `h_denominator_pos : 0 < kB * (b : ℝ)` using `mul_pos kB_pos h_b_pos`, which states that if `kB` is positive (proven by `kB_pos`) and `b` is positive (proven by `h_b_pos`), then their product is positive. - - We derive `h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ))` using `one_div_pos.mpr h_denominator_pos`, which states that if the denominator is positive, then the reciprocal is also positive. - - We then unfold the definition of `ofβ` to express `(ofβ b).toReal` as `(1 : ℝ) / (kB * (↑b : ℝ))`. - - Finally, we conclude that the goal `(1 : ℝ) / (kB * (b : ℝ)) > 0` is true by `h_quotient_pos`. QED. +The function `ofβ` produces strictly positive real-valued temperatures +for sufficiently large inverse temperature β. -/ lemma eventually_pos_ofβ : ∀ᶠ b : ℝ≥0 in atTop, ((Temperature.ofβ b : Temperature) : ℝ) > 0 := by + -- We start by proving that for sufficiently large `b : ℝ≥0`, + -- we have `1 ≤ b` using `Filter.eventually_ge_atTop 1`, + -- which states that eventually, all elements of the filter + -- at infinity are greater than or equal to `1`. + -- This gives us the hypothesis `h_eventually_b_ge_one`. have h_eventually_b_ge_one : ∀ᶠ b : ℝ≥0 in atTop, (1 : ℝ≥0) ≤ b := Filter.eventually_ge_atTop 1 + -- We then refine the goal using `h_eventually_b_ge_one.mono`, + -- which allows us to prove the desired property for all `b` that satisfy `1 ≤ b`. + -- The new goal is now `⊢ ∀ (x : ℝ≥0), 1 ≤ x → (ofβ x).toReal > 0`. refine h_eventually_b_ge_one.mono ?_ + -- We introduce `b : ℝ≥0` and the hypothesis `h_b_ge_one : 1 ≤ b` from the goal. + -- The goal is now `⊢ (ofβ b).toReal > 0`. intro b h_b_ge_one + -- We derive `h_b_pos : 0 < (b : ℝ)` using `zero_lt_one.trans_le h_b_ge_one`, + -- which states that if `0 < 1` and `1 ≤ b`, then `0 < b`. have h_b_pos : 0 < (b : ℝ) := by exact zero_lt_one.trans_le h_b_ge_one + -- We derive `h_denominator_pos : 0 < kB * (b : ℝ)` using `mul_pos kB_pos h_b_pos`, + -- which states that if `kB` is positive (proven by `kB_pos`) + -- and `b` is positive (proven by `h_b_pos`), then their product is positive. have h_denominator_pos : 0 < kB * (b : ℝ) := by exact mul_pos kB_pos h_b_pos + -- We derive `h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ))` + -- using `one_div_pos.mpr h_denominator_pos`, which states that if the denominator is positive, + -- then the reciprocal is also positive. have h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ)) := one_div_pos.mpr h_denominator_pos + -- We then unfold the definition of `ofβ` + -- to express `(ofβ b).toReal` as `{ val := ⟨1 / (kB * ↑b), ⋯⟩ }.toReal`. + -- The `⋯` represents the proof of non-negativity that we can ignore since it does not + -- affect the real value. unfold ofβ + -- Finally, we conclude that the goal `(1 : ℝ) / (kB * (b : ℝ)) > 0` is true by `h_quotient_pos`. + -- QED. exact h_quotient_pos -/-- Helper lemma: Positivity of the epsilon-delta bound construction. - -- Premises: - - `a : ℝ`: A positive real number (typically the constant in the denominator). - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `ε : ℝ`: A positive epsilon value (from the metric space definition). - - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. - -- Conclusion: - - The conclusion is `0 < (1 / (a * ε)) + 1`: The expression used in the epsilon-delta bound construction is strictly positive. - -- Proof: - - We first prove that `1 / (a * ε)` is positive. - - We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive (proof of `a` and `ε` being positive are given by `h_a_pos` and `h_ε_pos`). - - We then apply `one_div_pos.mpr h_product_pos` to conclude that `1 / (a * ε)` is positive, since the reciprocal of a positive number is also positive. We derive `h_reciprocal_pos : 0 < (1 / (a * ε))` from this. - - Finally, we conclude that `0 < (1 / (a * ε)) + 1` by applying `add_pos h_reciprocal_pos zero_lt_one`, which states that the sum of two positive numbers is positive. Here, `h_reciprocal_pos` provides the positivity of the first term, and `zero_lt_one` provides the positivity of the second term. QED. +/-- Helper lemma: Positivity of the epsilon-delta bound construction. (TODO) -/ private lemma tendsto_const_inv_mul_bound_pos (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : 0 < (1 / (a * ε)) + 1 := by + -- We first prove that `1 / (a * ε)` is positive. have h_reciprocal_pos : 0 < (1 / (a * ε)) := by + -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive (proof of `a` and `ε` being positive are given by `h_a_pos` and `h_ε_pos`). have h_product_pos : 0 < a * ε := by exact mul_pos h_a_pos h_ε_pos + -- We then apply `one_div_pos.mpr h_product_pos` to conclude that `1 / (a * ε)` is positive, since the reciprocal of a positive number is also positive. We derive `h_reciprocal_pos : 0 < (1 / (a * ε))` from this. exact one_div_pos.mpr h_product_pos + -- Finally, we conclude that `0 < (1 / (a * ε)) + 1` by applying `add_pos h_reciprocal_pos zero_lt_one`, which states that the sum of two positive numbers is positive. Here, `h_reciprocal_pos` provides the positivity of the first term, and `zero_lt_one` provides the positivity of the second term. QED. exact add_pos h_reciprocal_pos zero_lt_one /-- Helper lemma: Product positivity via transitivity of ordering. - -- Premises: - - `a : ℝ`: A positive real number. - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `b_lower_bound : ℝ`: A positive lower bound. - - `h_b_lower_bound_pos : 0 < b_lower_bound`: Hypothesis that `b_lower_bound` is strictly positive. - - `b : ℝ`: A real number greater than or equal to `b_lower_bound`. - - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is at least `b_lower_bound`. - -- Conclusion: - - The conclusion is `0 < a * b`: The product `a * b` is strictly positive. - -- Proof: - - From `0 < b_lower_bound ≤ b`, we obtain `0 < b` by transitivity using `lt_of_lt_of_le` applied to `h_b_lower_bound_pos` (`0 < b_lower_bound`) and `h_b_lower_bound_le_b` (`b_lower_bound ≤ b`). - - Then apply `mul_pos` to `h_a_pos` and `h_b_pos` to get `0 < a * b`. QED. -/ private lemma tendsto_const_inv_mul_product_pos_of_le (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : 0 < a * b := by + -- From `0 < b_lower_bound ≤ b`, we obtain `0 < b` by transitivity using `lt_of_lt_of_le` applied to `h_b_lower_bound_pos` (`0 < b_lower_bound`) and `h_b_lower_bound_le_b` (`b_lower_bound ≤ b`). have h_b_pos : 0 < b := lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b + -- Then apply `mul_pos` to `h_a_pos` and `h_b_pos` to get `0 < a * b`. QED. exact mul_pos h_a_pos h_b_pos /-- Helper lemma: Antitonicity of reciprocal function with constant multiplier. - -- Premises: - - `a : ℝ`: A positive constant multiplier. - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `b_lower_bound : ℝ`: A positive lower bound value. - - `b : ℝ`: A value greater than or equal to `b_lower_bound`. - - `h_product_b_lower_bound_pos : 0 < a * b_lower_bound`: Hypothesis that the product `a * b_lower_bound` is strictly positive. - - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is at least `b_lower_bound`. - -- Conclusion: - - The conclusion is `(1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)`: The reciprocal function `x ↦ 1 / (a * x)` is antitone (decreasing). - -- Proof: - - First, we derive `h_denom_le : (a * b_lower_bound) ≤ (a * b)` by applying `mul_le_mul_of_nonneg_left` to `h_b_lower_bound_le_b` and the nonnegativity of `a` (which follows from its positivity `h_a_pos`). - - Then we apply `one_div_le_one_div_of_le` to `h_product_b_lower_bound_pos` and `h_denom_le` to conclude that the reciprocal of the larger denominator is less than or equal to the reciprocal of the smaller denominator, which establishes the antitonicity. QED. -/ private lemma tendsto_const_inv_mul_reciprocal_antitone (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_product_b_lower_bound_pos : 0 < a * b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by + -- First, we derive `h_denom_le : (a * b_lower_bound) ≤ (a * b)` by applying `mul_le_mul_of_nonneg_left` to `h_b_lower_bound_le_b` and the nonnegativity of `a` (which follows from its positivity `h_a_pos`). have h_denom_le : (a * b_lower_bound) ≤ (a * b) := by exact mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos) + -- Then we apply `one_div_le_one_div_of_le` to `h_product_b_lower_bound_pos` and `h_denom_le` to conclude that the reciprocal of the larger denominator is less than or equal to the reciprocal of the smaller denominator, which establishes the antitonicity. QED. exact one_div_le_one_div_of_le h_product_b_lower_bound_pos h_denom_le /-- Helper lemma: Evaluating the function at the constructed bound yields a value less than `ε`. - -- Premises: - - `a : ℝ`: A positive constant. - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `ε : ℝ`: A positive epsilon value. - - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. - -- Conclusion: - - The conclusion is `(1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε`: Evaluating the function at the constructed bound yields a value less than `ε`, which is crucial for the epsilon-delta argument in proving convergence. - -- Proof: - - We first simplify the expression by performing field simplification with `field_simp` to rewrite the goal into `⊢ 1 < 1 + a * ε`. - - We then simplify further using `simp` to reduce the goal to `⊢ 0 < a * ε`. - - We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive. This gives us the desired inequality. QED. -/ private lemma tendsto_const_inv_mul_at_bound_lt_epsilon (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : (1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε := by + -- We first simplify the expression by performing field simplification with `field_simp` to rewrite the goal into `⊢ 1 < 1 + a * ε`. field_simp + -- We then simplify further using `simp` to reduce the goal to `⊢ 0 < a * ε`. simp + -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive. This gives us the desired inequality. QED. have h_product_pos : 0 < a * ε := by exact mul_pos h_a_pos h_ε_pos exact h_product_pos /-- Helper lemma: Conversion from nonnegative inequality to metric space distance. - -- Premises: - - `x : ℝ`: A real number. - - `h_x_nonneg : 0 ≤ x`: Hypothesis that `x` is nonnegative. - - `ε : ℝ`: A bound value. - - `h_x_lt_ε : x < ε`: Hypothesis that `x` is strictly less than `ε`. - -- Conclusion: - - The conclusion is `dist x 0 < ε`: The metric space distance from `x` to `0` is less than `ε`. - -- Proof: - - We first derive `h_abs_lt : |x| < ε` by calling `simpa [abs_of_nonneg h_x_nonneg] using h_x_lt_ε`, which simplifies the absolute value of `x` using the fact that `x` is nonnegative, and then applies the hypothesis that `x < ε`. - - We then rewrite the goal `dist x 0 < ε` using `Real.dist_eq` to express the distance in terms of absolute value (`dist x 0` is equal to `|x - 0|`), and use `sub_zero` to simplify this to `|x| < ε`. - - Finally, we conclude that `|x| < ε` is true by `h_abs_lt`. QED. -/ private lemma tendsto_const_inv_mul_nonneg_to_dist (x ε : ℝ) (h_x_nonneg : 0 ≤ x) (h_x_lt_ε : x < ε) : dist x 0 < ε := by + -- We first derive `h_abs_lt : |x| < ε` by calling `simpa [abs_of_nonneg h_x_nonneg] using h_x_lt_ε`, which simplifies the absolute value of `x` using the fact that `x` is nonnegative, and then applies the hypothesis that `x < ε`. have h_abs_lt : |x| < ε := by simpa [abs_of_nonneg h_x_nonneg] using h_x_lt_ε + -- We then rewrite the goal `dist x 0 < ε` using `Real.dist_eq` to express the distance in terms of absolute value (`dist x 0` is equal to `|x - 0|`), and use `sub_zero` to simplify this to `|x| < ε`. rw [Real.dist_eq, sub_zero] + -- Finally, we conclude that `|x| < ε` is true by `h_abs_lt`. QED. exact h_abs_lt /-- Helper lemma: Given a lower bound on `b` that ensures the function value is less than `ε`, we can conclude that for any `b` greater than or equal to that lower bound, the function value is nonnegative and less than `ε`. - -- Premises: - - `a : ℝ`: A positive constant. - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `ε : ℝ`: A positive epsilon value. - - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. - - `b_lower_bound : ℝ`: A positive lower bound for `b`. - - `h_b_lower_bound_pos : 0 < b_lower_bound`: Hypothesis that the lower bound is strictly positive. - - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is greater than or equal to the lower bound. - - `h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε`: Hypothesis that the function value at the lower bound is less than `ε`. - -- Conclusion: - - The conclusion is `0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε`: For any `b` greater than or equal to the lower bound, the value of the function `1 / (a * b)` is nonnegative and less than `ε`. - -- Proof: - - We first derive `h_prod_lower_pos : 0 < a * b_lower_bound` using `mul_pos h_a_pos h_b_lower_bound_pos`, which states that the product of two positive numbers is positive. - - We then derive `h_prod_pos : 0 < a * b` using the previous lemma `tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b`, which states that if `b` is greater than or equal to a positive lower bound, then the product `a * b` is also positive. - - Next, we derive `h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)` using the previous lemma `tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b h_a_pos h_prod_lower_pos h_b_lower_bound_le_b`, which states that the reciprocal function is antitone. - - We then derive `h_lt : (1 : ℝ) / (a * b) < ε` using `lt_of_le_of_lt h_rec_le h_at_bound_lt`, which states that if `1 / (a * b)` is less than or equal to `1 / (a * b_lower_bound)` and `1 / (a * b_lower_bound)` is less than `ε`, then `1 / (a * b)` is also less than `ε`. - - Finally, we derive `h_nonneg : 0 ≤ (1 : ℝ) / (a * b)` using `div_nonneg zero_le_one (le_of_lt h_prod_pos)`, which states that the reciprocal of a positive number is nonnegative. - - We conclude that `0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` by combining `h_nonneg` and `h_lt`. QED. -/ private lemma tendsto_const_inv_mul_nonneg_and_lt_of_bound (a ε b_lower_bound b : ℝ) (h_a_pos : 0 < a)(h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := by + -- We first derive `h_prod_lower_pos : 0 < a * b_lower_bound` using `mul_pos h_a_pos h_b_lower_bound_pos`, which states that the product of two positive numbers is positive. have h_prod_lower_pos : 0 < a * b_lower_bound := by exact mul_pos h_a_pos h_b_lower_bound_pos + -- We then derive `h_prod_pos : 0 < a * b` using the previous lemma `tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b`, which states that if `b` is greater than or equal to a positive lower bound, then the product `a * b` is also positive. have h_prod_pos : 0 < a * b := by exact tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b + -- Next, we derive `h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)` using the previous lemma `tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b h_a_pos h_prod_lower_pos h_b_lower_bound_le_b`, which states that the reciprocal function is antitone. have h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by exact tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b h_a_pos h_prod_lower_pos h_b_lower_bound_le_b + -- We then derive `h_lt : (1 : ℝ) / (a * b) < ε` using `lt_of_le_of_lt h_rec_le h_at_bound_lt`, which states that if `1 / (a * b)` is less than or equal to `1 / (a * b_lower_bound)` and `1 / (a * b_lower_bound)` is less than `ε`, then `1 / (a * b)` is also less than `ε`. have h_lt : (1 : ℝ) / (a * b) < ε := by exact lt_of_le_of_lt h_rec_le h_at_bound_lt + -- Finally, we derive `h_nonneg : 0 ≤ (1 : ℝ) / (a * b)` using `div_nonneg zero_le_one (le_of_lt h_prod_pos)`, which states that the reciprocal of a positive number is nonnegative. have h_nonneg : 0 ≤ (1 : ℝ) / (a * b) := by exact div_nonneg zero_le_one (le_of_lt h_prod_pos) + -- We conclude that `0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` by combining `h_nonneg` and `h_lt`. QED. exact ⟨h_nonneg, h_lt⟩ /-- Helper lemma: Given a lower bound on `b` that ensures the function value is less than `ε`, we can conclude that for any `b` greater than or equal to that lower bound, the distance from the function value to `0` is less than `ε`. - -- Premises: - - `a : ℝ`: A positive constant. - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `ε : ℝ`: A positive epsilon value. - - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. - - `b_lower_bound : ℝ`: A positive lower bound for `b`. - - `h_b_lower_bound_pos : 0 < b_lower_bound`: Hypothesis that the lower bound is strictly positive. - - `h_b_lower_bound_le_b : b_lower_bound ≤ b`: Hypothesis that `b` is greater than or equal to the lower bound. - - `h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε`: Hypothesis that the function value at the lower bound is less than `ε`. - -- Conclusion: - - The conclusion is `dist ((1 : ℝ) / (a * b)) (0 : ℝ) < ε`: The distance from the function value `1 / (a * b)` to `0` is less than `ε`. - -- Proof: - - We first derive `h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` using the previous lemma `tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt`, which states that for any `b` greater than or equal to the lower bound, the function value is nonnegative and less than `ε`. - - We then apply `tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε h_nonneg_and_lt.left h_nonneg_and_lt.right` to conclude that the distance from the function value to `0` is less than `ε`, using the fact that if a value is nonnegative and less than `ε`, then its distance to `0` is also less than `ε`. QED. -/ private lemma tendsto_const_inv_mul_dist_lt_of_bound (a ε b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : dist ((1 : ℝ) / (a * b)) (0 : ℝ) < ε := by + -- We first derive `h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` using the previous lemma `tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt`, which states that for any `b` greater than or equal to the lower bound, the function value is nonnegative and less than `ε`. have h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt + -- We then apply `tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε h_nonneg_and_lt.left h_nonneg_and_lt.right` to conclude that the distance from the function value to `0` is less than `ε`, using the fact that if a value is nonnegative and less than `ε`, then its distance to `0` is also less than `ε`. QED. exact tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε h_nonneg_and_lt.left h_nonneg_and_lt.right /-- Helper lemma: As `b` tends to infinity, the distance from the function value `1 / (a * b)` to `0` becomes less than any positive `ε` for sufficiently large `b`. - -- Premises: - - `a : ℝ`: A positive constant. - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `ε : ℝ`: A positive epsilon value. - - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. - -- Conclusion: - - The conclusion is `∀ᶠ b : ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε`: For sufficiently large values of `b`, the distance from the function value `1 / (a * b)` to `0` is less than `ε`. - -- Proof: - - We first construct a real number `B_real` defined as `(1 / (a * ε)) + 1`, which serves as a candidate lower bound for `b` to ensure that the function value is less than `ε`. - - We then derive `h_B_real_pos : 0 < B_real` using the previous lemma `tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos`, which states that the constructed bound is positive. - - We convert `B_real` to a nonnegative real number `B_nnreal` by taking the nonnegative part of `B_real`, ensuring that it is still positive. - - We derive `h_B_nnreal_pos : 0 < (B_nnreal : ℝ)` from `h_B_real_pos` by noting that the nonnegative part of a positive real number is also positive. - - We then refine the goal using `Filter.eventually_ge_atTop B_nnreal`, which states that eventually, all elements of the filter at infinity are greater than or equal to `B_nnreal`. The goal is now `⊢ ∀ (x : ℝ≥0), B_nnreal ≤ x → dist (1 / (a * ↑x)) 0 < ε`. - - We introduce `b : ℝ≥0` and the hypothesis `h_B_nnreal_le_b : B_nnreal ≤ b` from the goal. The goal is now `⊢ dist (1 / (a * ↑b)) 0 < ε`. - - We derive `h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε` using the previous lemma `tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos`, which states that evaluating the function at the constructed bound yields a value less than `ε`. - - Finally, we apply `tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt` to conclude that the distance from the function value to `0` is less than `ε` for any `b` greater than or equal to the constructed bound. QED. -/ private lemma tendsto_const_inv_mul_atTop_eventually_dist_lt (a : ℝ) (h_a_pos : 0 < a) (ε : ℝ) (h_ε_pos : 0 < ε) : ∀ᶠ b : ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε := by + -- We first construct a real number `B_real` defined as `(1 / (a * ε)) + 1`, which serves as a candidate lower bound for `b` to ensure that the function value is less than `ε`. let B_real : ℝ := (1 / (a * ε)) + 1 + -- We then derive `h_B_real_pos : 0 < B_real` using the previous lemma `tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos`, which states that the constructed bound is positive. have h_B_real_pos : 0 < B_real := by exact tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos + -- We convert `B_real` to a nonnegative real number `B_nnreal` by taking the nonnegative part of `B_real`, ensuring that it is still positive. let B_nnreal : ℝ≥0 := ⟨B_real, le_of_lt h_B_real_pos⟩ + -- We derive `h_B_nnreal_pos : 0 < (B_nnreal : ℝ)` from `h_B_real_pos` by noting that the nonnegative part of a positive real number is also positive. have h_B_nnreal_pos : 0 < (B_nnreal : ℝ) := by simpa [B_nnreal] using h_B_real_pos + -- We then refine the goal using `Filter.eventually_ge_atTop B_nnreal`, which states that eventually, all elements of the filter at infinity are greater than or equal to `B_nnreal`. The goal is now `⊢ ∀ (x : ℝ≥0), B_nnreal ≤ x → dist (1 / (a * ↑x)) 0 < ε`. refine (Filter.eventually_ge_atTop B_nnreal).mono ?_ + -- We introduce `b : ℝ≥0` and the hypothesis `h_B_nnreal_le_b : B_nnreal ≤ b` from the goal. The goal is now `⊢ dist (1 / (a * ↑b)) 0 < ε`. intro b h_B_nnreal_le_b + -- We derive `h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε` using the previous lemma `tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos`, which states that evaluating the function at the constructed bound yields a value less than `ε`. have h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε := by exact tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos + -- Finally, we apply `tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt` to conclude that the distance from the function value to `0` is less than `ε` for any `b` greater than or equal to the constructed bound. QED. exact tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt /-- Helper lemma: As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` in the sense of the metric space distance. - -- Premises: - - `a : ℝ`: A positive constant. - - `h_a_pos : 0 < a`: Hypothesis that `a` is strictly positive. - - `ε : ℝ`: A positive epsilon value. - - `h_ε_pos : 0 < ε`: Hypothesis that `ε` is strictly positive. - -- Conclusion: - - The conclusion is `Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ))`: As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` in the sense of the metric space distance. - -- Proof: - - We refine the goal using `Metric.tendsto_nhds.mpr`, which allows us to prove the convergence by showing that for every positive `ε`, the function values are eventually within `ε` of `0`. The new goal is now `⊢ ∀ ε > 0, ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. - - We introduce `ε : ℝ` and the hypothesis `h_ε_pos : 0 < ε`. The goal is now `⊢ ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. - - We apply the previous lemma `tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos` to conclude that for sufficiently large `b`, the distance from the function value to `0` is less than `ε`. QED. -/ private lemma tendsto_const_inv_mul_atTop (a : ℝ) (h_a_pos : 0 < a) : Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by + -- We refine the goal using `Metric.tendsto_nhds.mpr`, which allows us to prove the convergence by showing that for every positive `ε`, the function values are eventually within `ε` of `0`. The new goal is now `⊢ ∀ ε > 0, ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. refine Metric.tendsto_nhds.mpr ?_ + -- We introduce `ε : ℝ` and the hypothesis `h_ε_pos : 0 < ε`. The goal is now `⊢ ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. intro ε h_ε_pos + -- We apply the previous lemma `tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos` to conclude that for sufficiently large `b`, the distance from the function value to `0` is less than `ε`. QED. exact tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos /-- Lemma: As the inverse temperature `β` tends to infinity, the real-valued representation of the temperature `ofβ β` tends to `0` in the sense of the metric space distance. - -- Premises: - - None. - -- Conclusion: - - The conclusion is `Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ))`: As `β` tends to infinity, the real-valued representation of the temperature `ofβ β` tends to `0` in the sense of the metric space distance. - -- Proof: - - We apply the previous lemma `tendsto_const_inv_mul_atTop` with `a` set to `kB` and `h_a_pos` set to `kB_pos`, which states that as `b` tends to infinity, the function value `1 / (kB * b)` tends to `0`. Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. -/ lemma tendsto_toReal_ofβ_atTop : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ)) := by + -- We apply the previous lemma `tendsto_const_inv_mul_atTop` with `a` set to `kB` and `h_a_pos` set to `kB_pos`, which states that as `b` tends to infinity, the function value `1 / (kB * b)` tends to `0`. Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. exact tendsto_const_inv_mul_atTop kB kB_pos /-- As β → ∞, T = ofβ β → 0+ in ℝ (within Ioi 0). -/ From 935603b92aff1ba10c9eba69a5a7d3a01b7e2c49 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 04:59:06 +0000 Subject: [PATCH 03/12] docs(thermodynamics): improve clarity of lemmas in Temperature module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * TODO: From `tendsto_ofβ_atTop` downwards --- .../Thermodynamics/Temperature/Basic.lean | 243 +++++++++++++----- 1 file changed, 177 insertions(+), 66 deletions(-) diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index 462b53010..d0a292fe7 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -573,136 +573,247 @@ lemma eventually_pos_ofβ : ∀ᶠ b : ℝ≥0 in atTop, ((Temperature.ofβ b : -- using `one_div_pos.mpr h_denominator_pos`, which states that if the denominator is positive, -- then the reciprocal is also positive. have h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ)) := one_div_pos.mpr h_denominator_pos - -- We then unfold the definition of `ofβ` - -- to express `(ofβ b).toReal` as `{ val := ⟨1 / (kB * ↑b), ⋯⟩ }.toReal`. - -- The `⋯` represents the proof of non-negativity that we can ignore since it does not - -- affect the real value. - unfold ofβ - -- Finally, we conclude that the goal `(1 : ℝ) / (kB * (b : ℝ)) > 0` is true by `h_quotient_pos`. + -- We change the goal of `⊢ (ofβ b).toReal > 0` to its equivalent form + -- `⊢ (fun b => 1 / (kB * ↑b)) b > 0`. + change + (λ (b : ℝ≥0) => (1 : ℝ) / (kB * b)) b > 0 + -- We can apply `h_quotient_pos` to conclude that the goal is true, since `h_quotient_pos` states + -- that the expression `1 / (kB * (b : ℝ))` is positive, which is exactly what we need to show. -- QED. exact h_quotient_pos -/-- Helper lemma: Positivity of the epsilon-delta bound construction. (TODO) +/-- Helper lemma for `Temperature`: + +Positivity of the epsilon-delta bound construction. -/ -private lemma tendsto_const_inv_mul_bound_pos (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : 0 < (1 / (a * ε)) + 1 := by - -- We first prove that `1 / (a * ε)` is positive. +private lemma tendsto_const_inv_mul_bound_pos (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : + 0 < (1 / (a * ε)) + 1 := by + -- We derive `h_reciprocal_pos : 0 < (1 / (a * ε))` to show that the first term in the sum + -- is positive, which will allow us to conclude that the entire sum is positive. have h_reciprocal_pos : 0 < (1 / (a * ε)) := by - -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive (proof of `a` and `ε` being positive are given by `h_a_pos` and `h_ε_pos`). + -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, + -- which states that the product of two positive numbers is positive + -- (proof of `a` and `ε` being positive are given by `h_a_pos` and `h_ε_pos`). have h_product_pos : 0 < a * ε := by exact mul_pos h_a_pos h_ε_pos - -- We then apply `one_div_pos.mpr h_product_pos` to conclude that `1 / (a * ε)` is positive, since the reciprocal of a positive number is also positive. We derive `h_reciprocal_pos : 0 < (1 / (a * ε))` from this. + -- We then apply `one_div_pos.mpr h_product_pos` to conclude that `1 / (a * ε)` is positive, + -- since `h_product_pos` states that the denominator is positive. QED for this part. exact one_div_pos.mpr h_product_pos - -- Finally, we conclude that `0 < (1 / (a * ε)) + 1` by applying `add_pos h_reciprocal_pos zero_lt_one`, which states that the sum of two positive numbers is positive. Here, `h_reciprocal_pos` provides the positivity of the first term, and `zero_lt_one` provides the positivity of the second term. QED. + -- Finally, we apply `add_pos` to `h_reciprocal_pos` and `zero_lt_one` to conclude that the sum + -- `(1 / (a * ε)) + 1` is positive, since both terms are positive. QED. exact add_pos h_reciprocal_pos zero_lt_one -/-- Helper lemma: Product positivity via transitivity of ordering. +/-- Helper lemma for `Temperature`: + +Product positivity via transitivity of ordering. -/ -private lemma tendsto_const_inv_mul_product_pos_of_le (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : 0 < a * b := by - -- From `0 < b_lower_bound ≤ b`, we obtain `0 < b` by transitivity using `lt_of_lt_of_le` applied to `h_b_lower_bound_pos` (`0 < b_lower_bound`) and `h_b_lower_bound_le_b` (`b_lower_bound ≤ b`). +private lemma tendsto_const_inv_mul_product_pos_of_le (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) + (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : + 0 < a * b := by + -- We derive `h_b_pos : 0 < b` using `lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b`, + -- which states that if `b_lower_bound` is positive and `b_lower_bound ≤ b`, + -- then `b` is also positive. have h_b_pos : 0 < b := lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b - -- Then apply `mul_pos` to `h_a_pos` and `h_b_pos` to get `0 < a * b`. QED. + -- We then apply `mul_pos` to `h_a_pos` and `h_b_pos` to conclude that the product + -- `a * b` is positive. QED. exact mul_pos h_a_pos h_b_pos -/-- Helper lemma: Antitonicity of reciprocal function with constant multiplier. +/-- Helper lemma for `Temperature`: + +Antitonicity of reciprocal function with constant multiplier. -/ -private lemma tendsto_const_inv_mul_reciprocal_antitone (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_product_b_lower_bound_pos : 0 < a * b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by - -- First, we derive `h_denom_le : (a * b_lower_bound) ≤ (a * b)` by applying `mul_le_mul_of_nonneg_left` to `h_b_lower_bound_le_b` and the nonnegativity of `a` (which follows from its positivity `h_a_pos`). +private lemma tendsto_const_inv_mul_reciprocal_antitone (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) + (h_product_b_lower_bound_pos : 0 < a * b_lower_bound) + (h_b_lower_bound_le_b : b_lower_bound ≤ b) : + (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by + -- We derive `h_denom_le : (a * b_lower_bound) ≤ (a * b)` + -- using `mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos)`, which states that + -- if `b_lower_bound ≤ b` and `a` is non-negative, then multiplying both sides by `a` preserves the + -- inequality, giving us `a * b_lower_bound ≤ a * b`. have h_denom_le : (a * b_lower_bound) ≤ (a * b) := by exact mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos) - -- Then we apply `one_div_le_one_div_of_le` to `h_product_b_lower_bound_pos` and `h_denom_le` to conclude that the reciprocal of the larger denominator is less than or equal to the reciprocal of the smaller denominator, which establishes the antitonicity. QED. + -- Then we apply `one_div_le_one_div_of_le` to `h_product_b_lower_bound_pos` and `h_denom_le` + -- to conclude that the reciprocal of the larger denominator is less than or equal to the + -- reciprocal of the smaller denominator, which establishes the antitonicity. QED. exact one_div_le_one_div_of_le h_product_b_lower_bound_pos h_denom_le -/-- Helper lemma: Evaluating the function at the constructed bound yields a value less than `ε`. +/-- Helper lemma for `Temperature`: + +Evaluating the function at the constructed bound yields a value less than `ε`. -/ -private lemma tendsto_const_inv_mul_at_bound_lt_epsilon (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : (1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε := by - -- We first simplify the expression by performing field simplification with `field_simp` to rewrite the goal into `⊢ 1 < 1 + a * ε`. +private lemma tendsto_const_inv_mul_at_bound_lt_epsilon (a ε : ℝ) (h_a_pos : 0 < a) + (h_ε_pos : 0 < ε) : + (1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε := by + -- We first simplify the expression by performing field simplification with `field_simp` + -- to rewrite the goal into `⊢ 1 < 1 + a * ε`. field_simp -- We then simplify further using `simp` to reduce the goal to `⊢ 0 < a * ε`. simp - -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, which states that the product of two positive numbers is positive. This gives us the desired inequality. QED. + -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, + -- which states that the product of two positive numbers is positive. have h_product_pos : 0 < a * ε := by exact mul_pos h_a_pos h_ε_pos + -- Finally, we conclude that `⊢ 0 < a * ε` is true by `h_product_pos`. QED. exact h_product_pos -/-- Helper lemma: Conversion from nonnegative inequality to metric space distance. +/-- Helper lemma for `Temperature`: + +Conversion from nonnegative inequality to metric space distance. -/ -private lemma tendsto_const_inv_mul_nonneg_to_dist (x ε : ℝ) (h_x_nonneg : 0 ≤ x) (h_x_lt_ε : x < ε) : dist x 0 < ε := by - -- We first derive `h_abs_lt : |x| < ε` by calling `simpa [abs_of_nonneg h_x_nonneg] using h_x_lt_ε`, which simplifies the absolute value of `x` using the fact that `x` is nonnegative, and then applies the hypothesis that `x < ε`. - have h_abs_lt : |x| < ε := by - simpa [abs_of_nonneg h_x_nonneg] using h_x_lt_ε - -- We then rewrite the goal `dist x 0 < ε` using `Real.dist_eq` to express the distance in terms of absolute value (`dist x 0` is equal to `|x - 0|`), and use `sub_zero` to simplify this to `|x| < ε`. +private lemma tendsto_const_inv_mul_nonneg_to_dist (x ε : ℝ) (h_x_nonneg : 0 ≤ x) + (h_x_lt_ε : x < ε) : + dist x 0 < ε := by + -- We rewrite the goal `⊢ dist x 0 < ε` using `Real.dist_eq` to express the distance + -- in terms of absolute value (`dist x 0` is equal to `|x - 0|`), + -- and use `sub_zero` to simplify this to `⊢ |x| < ε`. rw [Real.dist_eq, sub_zero] - -- Finally, we conclude that `|x| < ε` is true by `h_abs_lt`. QED. + -- We derive `h_abs_lt : |x| < ε`, by rewriting `|x|` as `x` using `abs_of_nonneg h_x_nonneg`, + -- which states that if `x` is nonnegative, then `|x|` is equal to `x`. + -- Then we apply `h_x_lt_ε` to conclude that `|x| < ε` is true. + have h_abs_lt : |x| < ε := by + rw [abs_of_nonneg h_x_nonneg] + exact h_x_lt_ε + -- Finally, we conclude that `⊢ |x| < ε` is true by `h_abs_lt`. QED. exact h_abs_lt -/-- Helper lemma: Given a lower bound on `b` that ensures the function value is less than `ε`, we can conclude that for any `b` greater than or equal to that lower bound, the function value is nonnegative and less than `ε`. --/ -private lemma tendsto_const_inv_mul_nonneg_and_lt_of_bound (a ε b_lower_bound b : ℝ) (h_a_pos : 0 < a)(h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := by - -- We first derive `h_prod_lower_pos : 0 < a * b_lower_bound` using `mul_pos h_a_pos h_b_lower_bound_pos`, which states that the product of two positive numbers is positive. +/-- Helper lemma for `Temperature`: + +Given a lower bound on `b` that ensures the function value is less than `ε`, +we can conclude that for any `b` greater than or equal to that lower bound, +the function value is nonnegative and less than `ε`. +-/ +private lemma tendsto_const_inv_mul_nonneg_and_lt_of_bound (a ε b_lower_bound b : ℝ) + (h_a_pos : 0 < a)(h_b_lower_bound_pos : 0 < b_lower_bound) + (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : + 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := by + -- We derive `h_prod_lower_bound_pos : 0 < a * b_lower_bound` + -- using `mul_pos h_a_pos h_b_lower_bound_pos`, which states that the product of + -- two positive numbers is positive (proof of `a` and `b_lower_bound` being positive are given by + -- `h_a_pos` and `h_b_lower_bound_pos`). have h_prod_lower_pos : 0 < a * b_lower_bound := by exact mul_pos h_a_pos h_b_lower_bound_pos - -- We then derive `h_prod_pos : 0 < a * b` using the previous lemma `tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b`, which states that if `b` is greater than or equal to a positive lower bound, then the product `a * b` is also positive. + -- We then derive `h_prod_pos : 0 < a * b` using the previous lemma + -- `tendsto_const_inv_mul_product_pos_of_le`, which states that if `b` is greater than or equal + -- to a positive lower bound, then the product `a * b` is also positive. have h_prod_pos : 0 < a * b := by - exact tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b - -- Next, we derive `h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)` using the previous lemma `tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b h_a_pos h_prod_lower_pos h_b_lower_bound_le_b`, which states that the reciprocal function is antitone. + exact tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b + h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b + -- We then derive `h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)` + -- using the previous lemma `tendsto_const_inv_mul_reciprocal_antitone`, + -- which states that the reciprocal function is antitone. have h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by - exact tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b h_a_pos h_prod_lower_pos h_b_lower_bound_le_b - -- We then derive `h_lt : (1 : ℝ) / (a * b) < ε` using `lt_of_le_of_lt h_rec_le h_at_bound_lt`, which states that if `1 / (a * b)` is less than or equal to `1 / (a * b_lower_bound)` and `1 / (a * b_lower_bound)` is less than `ε`, then `1 / (a * b)` is also less than `ε`. + exact tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b + h_a_pos h_prod_lower_pos h_b_lower_bound_le_b + -- We then derive `h_lt : (1 : ℝ) / (a * b) < ε` using `lt_of_le_of_lt h_rec_le h_at_bound_lt`, + -- which states that if `1 / (a * b)` is less than or equal to `1 / (a * b_lower_bound)` + -- and `1 / (a * b_lower_bound)` is less than `ε`, then `1 / (a * b)` is also less than `ε`. have h_lt : (1 : ℝ) / (a * b) < ε := by exact lt_of_le_of_lt h_rec_le h_at_bound_lt - -- Finally, we derive `h_nonneg : 0 ≤ (1 : ℝ) / (a * b)` using `div_nonneg zero_le_one (le_of_lt h_prod_pos)`, which states that the reciprocal of a positive number is nonnegative. + -- We then derive `h_nonneg : 0 ≤ (1 : ℝ) / (a * b)` + -- using `div_nonneg zero_le_one (le_of_lt h_prod_pos)`, + -- which states that the reciprocal of a positive number is nonnegative. have h_nonneg : 0 ≤ (1 : ℝ) / (a * b) := by exact div_nonneg zero_le_one (le_of_lt h_prod_pos) - -- We conclude that `0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` by combining `h_nonneg` and `h_lt`. QED. + -- Finally, we conclude that both `0 ≤ (1 : ℝ) / (a * b)` and `(1 : ℝ) / (a * b) < ε` hold by + -- the proofs of `h_nonneg` and `h_lt`. QED. exact ⟨h_nonneg, h_lt⟩ -/-- Helper lemma: Given a lower bound on `b` that ensures the function value is less than `ε`, we can conclude that for any `b` greater than or equal to that lower bound, the distance from the function value to `0` is less than `ε`. +/-- Helper lemma for `Temperature`: + +Given a lower bound on `b` that ensures the function value is less than `ε`, +we can conclude that for any `b` greater than or equal to that lower bound, +the distance from the function value to `0` is less than `ε`. -/ private lemma tendsto_const_inv_mul_dist_lt_of_bound (a ε b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : dist ((1 : ℝ) / (a * b)) (0 : ℝ) < ε := by - -- We first derive `h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` using the previous lemma `tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt`, which states that for any `b` greater than or equal to the lower bound, the function value is nonnegative and less than `ε`. + -- We derive `h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` + -- using the previous lemma `tendsto_const_inv_mul_nonneg_and_lt_of_bound`, + -- which states that for any `b` greater than or equal to the lower bound, + -- the function value is nonnegative and less than `ε`. have h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt - -- We then apply `tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε h_nonneg_and_lt.left h_nonneg_and_lt.right` to conclude that the distance from the function value to `0` is less than `ε`, using the fact that if a value is nonnegative and less than `ε`, then its distance to `0` is also less than `ε`. QED. - exact tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε h_nonneg_and_lt.left h_nonneg_and_lt.right + -- Finally, we apply the previous lemma `tendsto_const_inv_mul_nonneg_to_dist` to conclude that + -- the distance from the function value to `0` is less than `ε`, since we have established that + -- the function value is nonnegative and less than `ε`. QED. + exact tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε + h_nonneg_and_lt.left h_nonneg_and_lt.right + +/-- Helper lemma for `Temperature`: + +As `b` tends to infinity, the distance from the function value `1 / (a * b)` to `0` +becomes less than any positive `ε` for sufficiently large `b`. -/-- Helper lemma: As `b` tends to infinity, the distance from the function value `1 / (a * b)` to `0` becomes less than any positive `ε` for sufficiently large `b`. +(TODO) -/ -private lemma tendsto_const_inv_mul_atTop_eventually_dist_lt (a : ℝ) (h_a_pos : 0 < a) (ε : ℝ) (h_ε_pos : 0 < ε) : ∀ᶠ b : ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε := by - -- We first construct a real number `B_real` defined as `(1 / (a * ε)) + 1`, which serves as a candidate lower bound for `b` to ensure that the function value is less than `ε`. +private lemma tendsto_const_inv_mul_atTop_eventually_dist_lt (a : ℝ) (h_a_pos : 0 < a) (ε : ℝ) + (h_ε_pos : 0 < ε) : ∀ᶠ b : + ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε := by + -- We construct a real number `B_real` defined as `(1 / (a * ε)) + 1`, + -- which serves as a candidate lower bound for `b` to ensure that the function value + -- is less than `ε`. let B_real : ℝ := (1 / (a * ε)) + 1 - -- We then derive `h_B_real_pos : 0 < B_real` using the previous lemma `tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos`, which states that the constructed bound is positive. + -- We then derive `h_B_real_pos : 0 < B_real` using the previous lemma + -- `tendsto_const_inv_mul_bound_pos`, which states that the constructed bound is positive. have h_B_real_pos : 0 < B_real := by exact tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos - -- We convert `B_real` to a nonnegative real number `B_nnreal` by taking the nonnegative part of `B_real`, ensuring that it is still positive. + -- We then define a nonnegative real number `B_nnreal` by taking the nonnegative part of + -- `B_real`, ensuring that it is still positive. let B_nnreal : ℝ≥0 := ⟨B_real, le_of_lt h_B_real_pos⟩ - -- We derive `h_B_nnreal_pos : 0 < (B_nnreal : ℝ)` from `h_B_real_pos` by noting that the nonnegative part of a positive real number is also positive. - have h_B_nnreal_pos : 0 < (B_nnreal : ℝ) := by simpa [B_nnreal] using h_B_real_pos - -- We then refine the goal using `Filter.eventually_ge_atTop B_nnreal`, which states that eventually, all elements of the filter at infinity are greater than or equal to `B_nnreal`. The goal is now `⊢ ∀ (x : ℝ≥0), B_nnreal ≤ x → dist (1 / (a * ↑x)) 0 < ε`. + -- We then derive `h_B_nnreal_pos : 0 < (B_nnreal : ℝ)` from `h_B_real_pos` + -- by noting that the coercion of `B_nnreal` to `ℝ` is exactly `B_real`, which is positive. QED. + have h_B_nnreal_pos : 0 < B_nnreal:= by + exact h_B_real_pos + -- We then refine the goal using `Filter.eventually_ge_atTop B_nnreal`, + -- which states that eventually, all elements of the filter at infinity are greater than or equal + -- to `B_nnreal`. The goal is now `⊢ ∀ (x : ℝ≥0), B_nnreal ≤ x → dist (1 / (a * ↑x)) 0 < ε`. refine (Filter.eventually_ge_atTop B_nnreal).mono ?_ - -- We introduce `b : ℝ≥0` and the hypothesis `h_B_nnreal_le_b : B_nnreal ≤ b` from the goal. The goal is now `⊢ dist (1 / (a * ↑b)) 0 < ε`. + -- We introduce `b : ℝ≥0` and the hypothesis `h_B_nnreal_le_b : B_nnreal ≤ b` from the goal. + --The goal is now `⊢ dist (1 / (a * ↑b)) 0 < ε`. intro b h_B_nnreal_le_b - -- We derive `h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε` using the previous lemma `tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos`, which states that evaluating the function at the constructed bound yields a value less than `ε`. + -- We derive `h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε` using the previous lemma + -- `tendsto_const_inv_mul_at_bound_lt_epsilon`, which states that evaluating the function + -- at the constructed bound yields a value less than `ε`. have h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε := by exact tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos - -- Finally, we apply `tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt` to conclude that the distance from the function value to `0` is less than `ε` for any `b` greater than or equal to the constructed bound. QED. - exact tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt + -- Finally, we apply `tendsto_const_inv_mul_dist_lt_of_bound` + -- to conclude that the distance from the function value to `0` is less than `ε` + -- for any `b` greater than or equal to the constructed bound. QED. + exact tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) + h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt + +/-- Helper lemma for `Temperature`: -/-- Helper lemma: As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` in the sense of the metric space distance. +As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` +in the sense ofthe metric space distance. -/ -private lemma tendsto_const_inv_mul_atTop (a : ℝ) (h_a_pos : 0 < a) : Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by - -- We refine the goal using `Metric.tendsto_nhds.mpr`, which allows us to prove the convergence by showing that for every positive `ε`, the function values are eventually within `ε` of `0`. The new goal is now `⊢ ∀ ε > 0, ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. +private lemma tendsto_const_inv_mul_atTop (a : ℝ) (h_a_pos : 0 < a) : + Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by + -- We refine the goal using `Metric.tendsto_nhds.mpr`, + -- which allows us to prove the convergence by showing that for every positive `ε`, + -- the function values are eventually within `ε` of `0`. + -- The new goal is now `⊢ ∀ ε > 0, ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. refine Metric.tendsto_nhds.mpr ?_ - -- We introduce `ε : ℝ` and the hypothesis `h_ε_pos : 0 < ε`. The goal is now `⊢ ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. + -- We introduce `ε : ℝ` and the hypothesis `h_ε_pos : 0 < ε` from the goal. + -- The goal is now `⊢ ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. intro ε h_ε_pos - -- We apply the previous lemma `tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos` to conclude that for sufficiently large `b`, the distance from the function value to `0` is less than `ε`. QED. + -- We apply the previous lemma `tendsto_const_inv_mul_atTop_eventually_dist_lt` + -- to conclude that for sufficiently large `b`, the distance from the function value to `0` + -- is less than `ε`. QED. exact tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos -/-- Lemma: As the inverse temperature `β` tends to infinity, the real-valued representation of the temperature `ofβ β` tends to `0` in the sense of the metric space distance. +/-- Lemma for `Temperature`: + +As the inverse temperature `β` tends to infinity, +the real-valued representation of the temperature `ofβ β` tends to `0` +in the sense of the metric space distance. -/ -lemma tendsto_toReal_ofβ_atTop : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ)) := by - -- We apply the previous lemma `tendsto_const_inv_mul_atTop` with `a` set to `kB` and `h_a_pos` set to `kB_pos`, which states that as `b` tends to infinity, the function value `1 / (kB * b)` tends to `0`. Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. +lemma tendsto_toReal_ofβ_atTop : + Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ)) := by + -- We apply the previous lemma `tendsto_const_inv_mul_atTop` + -- with `a` set to `kB` and `h_a_pos` set to `kB_pos`, + -- which states that as `b` tends to infinity, the function value `1 / (kB * b)` tends to `0`. + -- Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. exact tendsto_const_inv_mul_atTop kB kB_pos /-- As β → ∞, T = ofβ β → 0+ in ℝ (within Ioi 0). -/ From 6919a15484fbaa6f2dcc802252bbc4e3614f4dc4 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 07:11:46 +0000 Subject: [PATCH 04/12] docs(thermodynamics): enhance docstrings for Temperature.Basic functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Note: In `Calculus relating T and β`, the proofs are not really cleaned and humanized since it's kinda out of my league. --- .../Thermodynamics/Temperature/Basic.lean | 352 ++++++++++++------ 1 file changed, 247 insertions(+), 105 deletions(-) diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index d0a292fe7..22ce31d93 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -44,7 +44,9 @@ accessing the `val` field). -/ instance : Coe Temperature ℝ≥0 := ⟨fun (T : Temperature) => T.val⟩ -/-- Convert a `Temperature` to a real number. +/-- Function for `Temperature`: + +Convert a `Temperature` to a real number in `ℝ`. -/ noncomputable def toReal (T : Temperature) : ℝ := NNReal.toReal T.val @@ -131,7 +133,9 @@ lemma real_ge_zero (T : Temperature) : (T : ℝ) ≥ 0 := by -- `b ≥ a`. QED. exact zero_le_real T -/-- Calculate the inverse temperature `β` corresponding to a given temperature `T`. +/-- Function for `Temperature`: + +Calculate the inverse temperature `β` corresponding to a given temperature `T`. - Note: @@ -200,7 +204,9 @@ lemma β_toReal (T : Temperature) : (β T : ℝ) = (1 : ℝ) / (kB * (T : ℝ)) rfl -/-- Calculate the temperature associated with a given inverse temperature `β`. +/-- Function for `Temperature`: + +Calculate the temperature associated with a given inverse temperature `β`. -/ noncomputable def ofβ (β : ℝ≥0) : Temperature := -- Given the formula `1 / (kB * β)`, we need to show that this is non-negative to fit the type @@ -816,21 +822,54 @@ lemma tendsto_toReal_ofβ_atTop : -- Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. exact tendsto_const_inv_mul_atTop kB kB_pos -/-- As β → ∞, T = ofβ β → 0+ in ℝ (within Ioi 0). -/ -lemma tendsto_ofβ_atTop : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (nhdsWithin 0 (Set.Ioi 0)) := by - have h_to0 := tendsto_toReal_ofβ_atTop - have h_into : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓟 (Set.Ioi (0 : ℝ))) := - tendsto_principal.mpr (by simpa using Temperature.eventually_pos_ofβ) - have : Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) - atTop ((nhds (0 : ℝ)) ⊓ 𝓟 (Set.Ioi (0 : ℝ))) := - tendsto_inf.mpr ⟨h_to0, h_into⟩ - simpa [nhdsWithin] using this +/-- Lemma for `Temperature`: + +As the inverse temperature `β` tends to infinity, +the real-valued representation of the temperature `ofβ β` +tends to `0` from above (within the interval `(0, ∞)`). +-/ +lemma tendsto_ofβ_atTop : + Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) + atTop (nhdsWithin 0 (Set.Ioi 0)) := by + -- We derive `h_tendsto_nhds_zero` from + -- `tendsto_toReal_ofβ_atTop`, which states that as `β` + -- tends to infinity, the real-valued temperature + -- tends to `0` in the nhds sense. + have h_tendsto_nhds_zero := tendsto_toReal_ofβ_atTop + -- We derive `h_tendsto_principal_Ioi` which states that + -- as `β` tends to infinity, the real-valued temperature + -- eventually lies in the interval `(0, ∞)`, using + -- `tendsto_principal.mpr` and `eventually_pos_ofβ`. + have h_tendsto_principal_Ioi : + Tendsto (fun b : ℝ≥0 => + (Temperature.ofβ b : ℝ)) + atTop (𝓟 (Set.Ioi (0 : ℝ))) := + tendsto_principal.mpr + (by simpa using Temperature.eventually_pos_ofβ) + -- We combine `h_tendsto_nhds_zero` and + -- `h_tendsto_principal_Ioi` using `tendsto_inf.mpr` to + -- conclude that the function tends to `0` within the + -- infimum filter `nhds 0 ⊓ 𝓟 (Set.Ioi 0)`. + have h_tendsto_inf : + Tendsto (fun b : ℝ≥0 => + (Temperature.ofβ b : ℝ)) + atTop + ((nhds (0 : ℝ)) ⊓ 𝓟 (Set.Ioi (0 : ℝ))) := + tendsto_inf.mpr + ⟨h_tendsto_nhds_zero, h_tendsto_principal_Ioi⟩ + -- Since `nhdsWithin 0 (Set.Ioi 0)` is defined as + -- `nhds 0 ⊓ 𝓟 (Set.Ioi 0)`, the conclusion follows + -- directly from `h_tendsto_inf` by simplification. + -- QED. + simpa [nhdsWithin] using h_tendsto_inf /-! ### Conversion to and from `ℝ≥0` -/ open Constants -/-- Simplification function: Build a temperature from a nonnegative real number. +/-- Simplification function for `Temperature`: + +Build a temperature from a nonnegative real number. - Input: - `t` of type `ℝ≥0`: The nonnegative real number representing the temperature. @@ -840,72 +879,52 @@ open Constants @[simp] def ofNNReal (t : ℝ≥0) : Temperature := ⟨t⟩ -/-- Simplification lemma: The `val` field of a temperature constructed from a nonnegative real number `t` is equal to `t`. +/-- Simplification lemma for `Temperature`: -- Premises: - - `t` of type `ℝ≥0`: The nonnegative real number used to construct the temperature. -- Conclusion: - - The conclusion is `(ofNNReal t).val = t`: The `val` field of the temperature constructed from `t` is equal to `t`. -- Proof: - - The proof is straightforward as it directly follows from the definition of `ofNNReal`. - - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +The `val` field of a temperature constructed from a nonnegative real number `t` is equal to `t`. -/ @[simp] lemma ofNNReal_val (t : ℝ≥0) : (ofNNReal t).val = t := by + -- Both sides are definitionally equal by the definition of `ofNNReal`. QED. rfl -/-- Simplification lemma: Coercing a temperature constructed from a nonnegative real number `t` back to `ℝ≥0` returns `t`. +/-- Simplification lemma for `Temperature`: -- Premises: - - `t` of type `ℝ≥0`: The nonnegative real number used to construct the temperature. -- Conclusion: - - The conclusion is `((ofNNReal t : Temperature) : ℝ≥0) = t`: Coercing the temperature back to `ℝ≥0` returns the original `t`. -- Proof: - - The proof is straightforward as it directly follows from the definition of `ofNNReal` and the coercion. - - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +Coercing a temperature constructed from a nonnegative real number `t` back to `ℝ≥0` returns `t`. -/ @[simp] lemma coe_ofNNReal_coe (t : ℝ≥0) : ((ofNNReal t : Temperature) : ℝ≥0) = t := by + -- Both sides are definitionally equal by the definition of `ofNNReal` and the coercion. QED. rfl -/-- Simplification lemma: Coercing a temperature constructed from a nonnegative real number `t` to `ℝ` returns `t`. +/-- Simplification lemma for `Temperature`: -- Premises: - - `t` of type `ℝ≥0`: The nonnegative real number used to construct the temperature. -- Conclusion: - - The conclusion is `((ofNNReal t : Temperature) : ℝ) = t`: Coercing the temperature to `ℝ` returns the original `t`. -- Proof: - - The proof is straightforward as it directly follows from the definition of `ofNNReal` and the coercion. - - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +Coercing a temperature constructed from a nonnegative real number `t` to `ℝ` returns `t`. -/ @[simp] lemma coe_ofNNReal_real (t : ℝ≥0) : ((⟨t⟩ : Temperature) : ℝ) = t := by + -- Both sides are definitionally equal by the definition of `ofNNReal` and the coercion. QED. rfl -/-- Simplification function: Build a temperature from a real number, given a proof that it is nonnegative. +/-- Simplification function for `Temperature`: -- Input: - - `t` of type `ℝ`: The real number representing the temperature. - - `h_zero_le_t` of type `0 ≤ t`: A proof that the real number is nonnegative. -- Output: - - Result of type `Temperature`: The temperature constructed from the real number `t`. +Build a temperature from a real number, given a proof that it is nonnegative. -/ @[simp] -noncomputable def ofRealNonneg (t : ℝ) (h_zero_le_t : 0 ≤ t) : Temperature := ofNNReal ⟨t, h_zero_le_t⟩ +noncomputable def ofRealNonneg (t : ℝ) (h_zero_le_t : 0 ≤ t) : Temperature := by + -- Apply `ofNNReal` to the nonnegative real number `t` to construct the temperature, + -- using the fact that `t` can be coerced to `ℝ≥0` since it is nonnegative. + exact ofNNReal ⟨t, h_zero_le_t⟩ -/-- Simplification lemma: The `val` field of a temperature constructed from a nonnegative real number `t` is equal to `⟨t, h_zero_le_t⟩`. +/-- Simplification lemma for `Temperature`: -- Premises: - - `t` of type `ℝ` (implicit): The real number used to construct the temperature. - - `h_zero_le_t` of type `0 ≤ t`: A proof that the real number is nonnegative. -- Conclusion: - - The conclusion is `(ofRealNonneg t h_zero_le_t).val = ⟨t, h_zero_le_t⟩`: The `val` field of the temperature constructed from `t` is equal to `⟨t, h_zero_le_t⟩`. -- Proof: - - The proof is straightforward as it directly follows from the definition of `ofRealNonneg`. - - We use `rfl` (reflexivity of equality) to conclude that both sides are equal. QED. +The `val` field of a temperature constructed from a nonnegative real number `t` +is equal to `⟨t, h_zero_le_t⟩`. -/ @[simp] -lemma ofRealNonneg_val {t : ℝ} (h_zero_le_t : 0 ≤ t) : (ofRealNonneg t h_zero_le_t).val = ⟨t, h_zero_le_t⟩ := by +lemma ofRealNonneg_val {t : ℝ} (h_zero_le_t : 0 ≤ t) : + (ofRealNonneg t h_zero_le_t).val = ⟨t, h_zero_le_t⟩ := by + -- Both sides are definitionally equal by the definition of `ofRealNonneg`. QED. rfl /-! ### Calculus relating T and β -/ @@ -913,47 +932,104 @@ lemma ofRealNonneg_val {t : ℝ} (h_zero_le_t : 0 ≤ t) : (ofRealNonneg t h_zer open Set open scoped ENNReal -/-- Map a real `t` to the inverse temperature `β` corresponding to the temperature `Real.toNNReal t` -(`max t 0`), returned as a real number. -/ -noncomputable def βFromReal (t : ℝ) : ℝ := - ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) +/-- Function for `Temperature`: -/-- Explicit closed-form for `β_fun_T t` when `t > 0`. -/ -lemma β_fun_T_formula (t : ℝ) (ht : 0 < t) : +Map a real number `t` to the inverse temperature `β` corresponding to +the temperature `Real.toNNReal t` (`max t 0`), returned as a real number. +-/ +noncomputable def βFromReal (t : ℝ) : ℝ := ((Temperature.ofNNReal (Real.toNNReal t)).β) + +/-- Lemma for `Temperature`: + +Explicit closed-form for `βFromReal t` when `t > 0`: `βFromReal t = 1 / (kB * t)`. +-/ +lemma β_fun_T_formula (t : ℝ) (h_t_pos : 0 < t) : βFromReal t = (1 : ℝ) / (kB * t) := by - have ht0 : (0 : ℝ) ≤ t := ht.le - have : ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = (1 : ℝ) / (kB * t) := by + -- We derive `h_t_nonneg : 0 ≤ t` from `h_t_pos` by weakening strict + -- inequality to non-strict inequality. + have h_t_nonneg : (0 : ℝ) ≤ t := h_t_pos.le + -- We derive `h_beta_formula` which states that the explicit formula + -- for `β` applied to `Real.toNNReal t` equals `1 / (kB * t)`, + -- by simplifying using the definitions of `β`, `ofNNReal`, `toReal`, + -- and the fact that `Real.toNNReal t = t` when `t ≥ 0`. + have h_beta_formula : + ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = (1 : ℝ) / (kB * t) := by simp [Temperature.β, Temperature.ofNNReal, Temperature.toReal, - Real.toNNReal_of_nonneg ht0, one_div, mul_comm] - simpa [βFromReal] using this + Real.toNNReal_of_nonneg h_t_nonneg, one_div, mul_comm] + -- We conclude by simplifying the definition of `βFromReal` and + -- applying `h_beta_formula`. QED. + simpa [βFromReal] using h_beta_formula + +/-- Lemma for `Temperature`: -/-- On `Ioi 0`, `β_fun_T t` equals `1 / (kB * t)`. -/ -lemma β_fun_T_eq_on_Ioi : - EqOn βFromReal (fun t : ℝ => (1 : ℝ) / (kB * t)) (Set.Ioi 0) := by - intro t ht - exact β_fun_T_formula t ht +On the interval `(0, ∞)`, `βFromReal t` equals `1 / (kB * t)`. +-/ +lemma β_fun_T_eq_on_Ioi : EqOn βFromReal (fun t : ℝ => (1 : ℝ) / (kB * t)) (Set.Ioi 0) := by + -- We introduce `t : ℝ` and the hypothesis + -- `h_t_pos : t ∈ Set.Ioi 0` (i.e. `0 < t`) from the goal. + intro t h_t_pos + -- We simplify `h_t_pos` to extract the inequality `0 < t`. + simp at h_t_pos + -- We apply `β_fun_T_formula t h_t_pos` to conclude that + -- `βFromReal t = 1 / (kB * t)`. QED. + exact β_fun_T_formula t h_t_pos -lemma deriv_β_wrt_T (T : Temperature) (hT_pos : 0 < T.val) : - HasDerivWithinAt βFromReal (-1 / (kB * (T.val : ℝ)^2)) (Set.Ioi 0) (T.val : ℝ) := by +/-- Lemma for `Temperature`: + +The function `βFromReal` has derivative `-1 / (kB * T²)` within the +interval `(0, ∞)` at the point `T.val`, when `T` is strictly positive. +-/ +lemma deriv_β_wrt_T (T : Temperature) (h_T_pos : 0 < T.val) : HasDerivWithinAt βFromReal + (-1 / (kB * (T.val : ℝ)^2)) (Set.Ioi 0) (T.val : ℝ) := by + -- We define `f : ℝ → ℝ` as the explicit formula + -- `f t = 1 / (kB * t)`, which is the closed form of + -- `βFromReal` on `(0, ∞)`. let f : ℝ → ℝ := fun t => (1 : ℝ) / (kB * t) - have h_eq : EqOn βFromReal f (Set.Ioi 0) := β_fun_T_eq_on_Ioi - have hTne : (T.val : ℝ) ≠ 0 := ne_of_gt hT_pos - have hf_def : f = fun t : ℝ => (kB)⁻¹ * t⁻¹ := by + -- We derive `h_eq_on : EqOn βFromReal f (Set.Ioi 0)` + -- using `β_fun_T_eq_on_Ioi`, which states that + -- `βFromReal` and `f` agree on `(0, ∞)`. + have h_eq_on : EqOn βFromReal f (Set.Ioi 0) := + β_fun_T_eq_on_Ioi + -- We derive `h_T_ne_zero : (T.val : ℝ) ≠ 0` from + -- `h_T_pos` using `ne_of_gt`, since a strictly positive + -- number is nonzero. + have h_T_ne_zero : (T.val : ℝ) ≠ 0 := + ne_of_gt h_T_pos + -- We derive `h_f_def` which rewrites `f` in terms of + -- inverses: `f = fun t => kB⁻¹ * t⁻¹`, by case-splitting + -- on whether `t = 0` and simplifying. + have h_f_def : + f = fun t : ℝ => (kB)⁻¹ * t⁻¹ := by funext t - by_cases ht : t = 0 - · simp [f, ht] + -- We case-split on whether `t = 0`. + by_cases h_t_eq_zero : t = 0 + -- If `t = 0`, both sides simplify to `0`. + · simp [f, h_t_eq_zero] + -- If `t ≠ 0`, we simplify and apply `ring`. QED. · simp [f, one_div, *] at * ring + -- We derive `h_inv` which states that the derivative of + -- `t⁻¹` at `T.val` is `-(T.val²)⁻¹`, using + -- `hasDerivAt_inv` with `h_T_ne_zero`. have h_inv : HasDerivAt (fun t : ℝ => t⁻¹) (-((T.val : ℝ) ^ 2)⁻¹) (T.val : ℝ) := by - simpa using (hasDerivAt_inv (x := (T.val : ℝ)) hTne) + simpa using + (hasDerivAt_inv (x := (T.val : ℝ)) h_T_ne_zero) + -- We derive `h_deriv_aux` which states the derivative of + -- `kB⁻¹ * t⁻¹` at `T.val` is `kB⁻¹ * (-(T.val²)⁻¹)`, + -- by applying the constant-multiple rule to `h_inv`. have h_deriv_aux : HasDerivAt (fun t : ℝ => (kB)⁻¹ * t⁻¹) - ((kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹)) (T.val : ℝ) := + ((kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹)) + (T.val : ℝ) := h_inv.const_mul ((kB)⁻¹) + -- We derive `h_pow_simp` which simplifies the derivative + -- expression `kB⁻¹ * (-(T.val²)⁻¹)` to the target form + -- `-1 / (kB * T.val²)`, using algebraic manipulations. have h_pow_simp : - (kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹) = -1 / (kB * (T.val : ℝ)^2) := by + (kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹) = + -1 / (kB * (T.val : ℝ)^2) := by calc (kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹) = -((kB)⁻¹ * ((T.val : ℝ) ^ 2)⁻¹) := by @@ -962,34 +1038,100 @@ lemma deriv_β_wrt_T (T : Temperature) (hT_pos : 0 < T.val) : simp [one_div] _ = -1 / (kB * (T.val : ℝ) ^ 2) := by rw [one_div] - field_simp [pow_two, mul_comm, mul_left_comm, mul_assoc, kB_ne_zero, hTne] + field_simp [pow_two, mul_comm, + mul_left_comm, mul_assoc, + kB_ne_zero, h_T_ne_zero] + -- We derive `h_deriv_f` which states that `f` has + -- derivative `-1 / (kB * T.val²)` at `T.val`, by + -- combining `h_f_def`, `h_pow_simp`, and `h_deriv_aux`. have h_deriv_f : - HasDerivAt f (-1 / (kB * (T.val : ℝ)^2)) (T.val : ℝ) := by - simpa [hf_def, h_pow_simp] using h_deriv_aux - have h_mem : (T.val : ℝ) ∈ Set.Ioi (0 : ℝ) := hT_pos - exact (h_deriv_f.hasDerivWithinAt).congr h_eq (h_eq h_mem) + HasDerivAt f + (-1 / (kB * (T.val : ℝ)^2)) + (T.val : ℝ) := by + simpa [h_f_def, h_pow_simp] using h_deriv_aux + -- We derive `h_mem : (T.val : ℝ) ∈ Set.Ioi 0` from + -- `h_T_pos`, confirming that the evaluation point lies + -- in the domain. + have h_mem : (T.val : ℝ) ∈ Set.Ioi (0 : ℝ) := + h_T_pos + -- We conclude by converting `h_deriv_f` to a + -- `HasDerivWithinAt` and applying `congr` with `h_eq_on` + -- to replace `f` by `βFromReal` on the set. QED. + exact (h_deriv_f.hasDerivWithinAt).congr + h_eq_on (h_eq_on h_mem) -/-- Chain rule for β(T) : d/dT F(β(T)) = F'(β(T)) * (-1 / (kB * T^2)), within `Ioi 0`. -/ +/-- Lemma for `Temperature`: + +Chain rule for `β(T)`: if `F` has derivative `F'` at `β(T)` within +`(0, ∞)`, then the composition `t ↦ F(βFromReal(t))` has derivative +`F' * (-1 / (kB * T²))` within `(0, ∞)` at `T.val`. +-/ lemma chain_rule_T_β {F : ℝ → ℝ} {F' : ℝ} - (T : Temperature) (hT_pos : 0 < T.val) - (hF_deriv : HasDerivWithinAt F F' (Set.Ioi 0) (T.β : ℝ)) : + (T : Temperature) (h_T_pos : 0 < T.val) + (h_F_deriv : HasDerivWithinAt F F' (Set.Ioi 0) (T.β : ℝ)) : HasDerivWithinAt (fun t : ℝ => F (βFromReal t)) - (F' * (-1 / (kB * (T.val : ℝ)^2))) (Set.Ioi 0) (T.val : ℝ) := by - have hβ_deriv := deriv_β_wrt_T (T:=T) hT_pos - have h_map : Set.MapsTo βFromReal (Set.Ioi 0) (Set.Ioi 0) := by - intro t ht - have ht_pos : 0 < t := ht - have : 0 < (1 : ℝ) / (kB * t) := by - have : 0 < kB * t := mul_pos kB_pos ht_pos - exact one_div_pos.mpr this - have h_eqt : βFromReal t = (1 : ℝ) / (kB * t) := β_fun_T_eq_on_Ioi ht - simpa [h_eqt] using this - have h_β_at_T : βFromReal (T.val : ℝ) = (T.β : ℝ) := by - have hTposR : 0 < (T.val : ℝ) := hT_pos - have h_eqt := β_fun_T_eq_on_Ioi hTposR - simpa [Temperature.β, Temperature.toReal] using h_eqt - have hF_deriv' : HasDerivWithinAt F F' (Set.Ioi 0) (βFromReal (T.val : ℝ)) := by - simpa [h_β_at_T] using hF_deriv - have h_comp := hF_deriv'.comp (T.val : ℝ) hβ_deriv h_map - simpa [mul_comm] using h_comp + (F' * (-1 / (kB * (T.val : ℝ)^2))) + (Set.Ioi 0) (T.val : ℝ) := by + -- We derive `h_β_deriv` from `deriv_β_wrt_T`, which + -- gives the derivative of `βFromReal` at `T.val`. + have h_β_deriv := + deriv_β_wrt_T (T := T) h_T_pos + -- We derive `h_maps_to` which states that `βFromReal` + -- maps `(0, ∞)` into `(0, ∞)`, i.e. positive inputs + -- produce positive outputs. + have h_maps_to : + Set.MapsTo βFromReal (Set.Ioi 0) (Set.Ioi 0) := by + -- We introduce `t : ℝ` and the hypothesis + -- `h_t_pos : t ∈ Set.Ioi 0` (i.e. `0 < t`). + intro t h_t_pos + -- We derive `h_kB_mul_t_pos : 0 < kB * t` using + -- `mul_pos kB_pos h_t_pos`. + have h_kB_mul_t_pos : 0 < kB * t := + mul_pos kB_pos h_t_pos + -- We derive `h_quotient_pos : 0 < 1 / (kB * t)` using + -- `one_div_pos.mpr h_kB_mul_t_pos`. + have h_quotient_pos : 0 < (1 : ℝ) / (kB * t) := + one_div_pos.mpr h_kB_mul_t_pos + -- We derive `h_βFromReal_eq` which states that + -- `βFromReal t = 1 / (kB * t)` on `(0, ∞)`. + have h_βFromReal_eq : + βFromReal t = (1 : ℝ) / (kB * t) := + β_fun_T_eq_on_Ioi h_t_pos + -- We conclude by rewriting `βFromReal t` with + -- `h_βFromReal_eq` and applying `h_quotient_pos`. QED. + simpa [h_βFromReal_eq] using h_quotient_pos + -- We derive `h_β_at_T` which states that + -- `βFromReal (T.val : ℝ) = (T.β : ℝ)`, i.e. the + -- explicit formula agrees with the definition of `β`. + have h_β_at_T : + βFromReal (T.val : ℝ) = (T.β : ℝ) := by + -- We derive `h_T_pos_real : 0 < (T.val : ℝ)` from + -- `h_T_pos`. + have h_T_pos_real : 0 < (T.val : ℝ) := h_T_pos + -- We derive `h_βFromReal_eq_at_T` from + -- `β_fun_T_eq_on_Ioi h_T_pos_real`. + have h_βFromReal_eq_at_T := + β_fun_T_eq_on_Ioi h_T_pos_real + -- We conclude by simplifying with the definitions of + -- `β` and `toReal`. QED. + simpa [Temperature.β, Temperature.toReal] + using h_βFromReal_eq_at_T + -- We derive `h_F_deriv_at_βFromReal` which rewrites + -- `h_F_deriv` to use `βFromReal (T.val)` instead of + -- `(T.β : ℝ)`, using `h_β_at_T`. + have h_F_deriv_at_βFromReal : + HasDerivWithinAt F F' + (Set.Ioi 0) (βFromReal (T.val : ℝ)) := by + simpa [h_β_at_T] using h_F_deriv + -- We derive `h_composition` by applying the chain rule + -- (`HasDerivWithinAt.comp`) to compose `F` with + -- `βFromReal`, using `h_F_deriv_at_βFromReal`, + -- `h_β_deriv`, and `h_maps_to`. + have h_composition := + h_F_deriv_at_βFromReal.comp + (T.val : ℝ) h_β_deriv h_maps_to + -- We conclude by simplifying `h_composition` with + -- `mul_comm` to match the target derivative expression. + -- QED. + simpa [mul_comm] using h_composition end Temperature From dc469816fe2e0e51d745b568de4a13f9e1058863 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 07:15:47 +0000 Subject: [PATCH 05/12] =?UTF-8?q?docs(thermodynamics):=20add=20note=20to?= =?UTF-8?q?=20=CE=B2FromReal=20function=20(questioning=20about=20the=20typ?= =?UTF-8?q?e=20definition)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PhysLean/Thermodynamics/Temperature/Basic.lean | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index 22ce31d93..7510a9f78 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -936,6 +936,10 @@ open scoped ENNReal Map a real number `t` to the inverse temperature `β` corresponding to the temperature `Real.toNNReal t` (`max t 0`), returned as a real number. + +Note: + +1. Why `ℝ` instead of `ℝ≥0`, if `β` is of type `ℝ≥0`? -/ noncomputable def βFromReal (t : ℝ) : ℝ := ((Temperature.ofNNReal (Real.toNNReal t)).β) From 8ff34dcf517ae78d1e26e71b5e46a84223400a58 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 07:17:21 +0000 Subject: [PATCH 06/12] style(thermodynamics): fix typo in helper lemma comment --- PhysLean/Thermodynamics/Temperature/Basic.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index 7510a9f78..8e333e4be 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -791,7 +791,7 @@ private lemma tendsto_const_inv_mul_atTop_eventually_dist_lt (a : ℝ) (h_a_pos /-- Helper lemma for `Temperature`: As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` -in the sense ofthe metric space distance. +in the sense of the metric space distance. -/ private lemma tendsto_const_inv_mul_atTop (a : ℝ) (h_a_pos : 0 < a) : Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by From 3eb4efe13e7cac961a680f379dae598a649fff6e Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 07:48:48 +0000 Subject: [PATCH 07/12] feat(thermodynamics): break the large `Basic.lean` file into smaller files --- PhysLean.lean | 3 + .../CanonicalEnsemble/Lemmas.lean | 1 + .../Thermodynamics/Temperature/Basic.lean | 781 +----------------- .../Thermodynamics/Temperature/Calculus.lean | 238 ++++++ .../Temperature/Convergence.lean | 347 ++++++++ .../Temperature/Regularity.lean | 261 ++++++ 6 files changed, 861 insertions(+), 770 deletions(-) create mode 100644 PhysLean/Thermodynamics/Temperature/Calculus.lean create mode 100644 PhysLean/Thermodynamics/Temperature/Convergence.lean create mode 100644 PhysLean/Thermodynamics/Temperature/Regularity.lean diff --git a/PhysLean.lean b/PhysLean.lean index 920ac6ecc..e4a5d5add 100644 --- a/PhysLean.lean +++ b/PhysLean.lean @@ -383,6 +383,9 @@ import PhysLean.StringTheory.FTheory.SU5.Quanta.TenQuanta import PhysLean.Thermodynamics.Basic import PhysLean.Thermodynamics.IdealGas.Basic import PhysLean.Thermodynamics.Temperature.Basic +import PhysLean.Thermodynamics.Temperature.Calculus +import PhysLean.Thermodynamics.Temperature.Convergence +import PhysLean.Thermodynamics.Temperature.Regularity import PhysLean.Thermodynamics.Temperature.TemperatureUnits import PhysLean.Units.Basic import PhysLean.Units.Dimension diff --git a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean index 41691a8ab..70a45d31c 100644 --- a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean +++ b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Lemmas.lean @@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE. Authors: Matteo Cipollina, Joseph Tooby-Smith -/ import PhysLean.StatisticalMechanics.CanonicalEnsemble.Basic +import PhysLean.Thermodynamics.Temperature.Calculus /-! # Canonical Ensemble: Thermodynamic Identities and Relations diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index 8e333e4be..ddb530644 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -3,20 +3,28 @@ Copyright (c) 2026 Joseph Tooby-Smith. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Trong-Nghia Be, Matteo Cipollina, Tan-Phuoc-Hung Le, Joseph Tooby-Smith -/ -import Mathlib.Analysis.Calculus.Deriv.Inv import Mathlib.Analysis.InnerProductSpace.Basic import PhysLean.StatisticalMechanics.BoltzmannConstant -import PhysLean.Meta.TODO.Basic /-! # Temperature -In this module we define the type `Temperature`, corresponding to absolute thermodynamic temperature measured in kelvin. +In this module we define the type `Temperature`, corresponding to absolute thermodynamic temperature +measured in kelvin. This is the version of temperature most often used in undergraduate and non-mathematical physics. For affine display scales with offsets (such as Celsius and Fahrenheit), see `PhysLean.Thermodynamics.Temperature.TemperatureScales`. + +For regularity properties of `ofβ`, see +`PhysLean.Thermodynamics.Temperature.Regularity`. + +For convergence results, see +`PhysLean.Thermodynamics.Temperature.Convergence`. + +For calculus relating T and β, see +`PhysLean.Thermodynamics.Temperature.Calculus`. -/ open NNReal @@ -309,564 +317,8 @@ lemma β_pos (T : Temperature) (h_T_pos : 0 < T.val) : 0 < (T.β : ℝ) := by -- All cases have been proven. QED. exact kB_pos -/-! ### Regularity of `ofβ` === TODO TIL THE END OF THE FILE -/ - -open Filter Topology - -/-- Helper lemma for `Temperature`: - -The denominator of `ofβ` is nonnegative. --/ -private lemma ofβ_den_nonneg (b : ℝ≥0) : 0 ≤ kB * (b : ℝ) := by - -- We apply `mul_nonneg` to show that the product `kB * (b : ℝ)` is nonnegative by showing that - -- both factors are nonnegative. - apply mul_nonneg - -- `case ha`: The goal is `⊢ 0 ≤ kB`, which is true by the lemma `kB_nonneg`, since the Boltzmann - -- constant is a positive physical constant. QED for this case. - · exact kB_nonneg - -- `case hb`: The goal is `⊢ 0 ≤ (b : ℝ)`, which is true by the fact that `b` of type `ℝ≥0` - -- carries the proof `b.property : 0 ≤ (b : ℝ)`. QED for this case. - · exact b.property - -- All cases have been proven. QED. - -/-- Helper lemma for `Temperature`: - -The real-valued expression `1 / (kB * b)` is nonnegative. --/ -private lemma ofβ_real_nonneg (b : ℝ≥0) : 0 ≤ (1 : ℝ) / (kB * (b : ℝ)) := by - -- We apply `div_nonneg` to show that the fraction `1 / (kB * b)` is nonnegative by showing that - -- both the numerator and the denominator are nonnegative. - apply div_nonneg - -- `case ha`: The goal is `⊢ 0 ≤ 1`, which is true by the lemma `zero_le_one`. QED for this case. - · exact zero_le_one - -- `case hb`: The goal is `⊢ 0 ≤ kB * (b : ℝ)`, which is true by the lemma `ofβ_den_nonneg b`. - -- QED for this case. - · exact ofβ_den_nonneg b - -- All cases have been proven. QED. - -/-- Helper lemma for `Temperature`: - -Continuity at a positive point for the real formula `(t : ℝ) ↦ (1 : ℝ) / (kB * t)`. --/ -private lemma ofβ_realExpr_continuousAt_real (x : ℝ≥0) (h_x_pos : 0 < x) : - ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ) := by - -- We refine the goal using `ContinuousAt.div₀`, which requires us to prove continuity of the - -- numerator and denominator separately: - refine ContinuousAt.div₀ ?_ ?_ ?_ - -- `case refine_1`: The goal is `⊢ ContinuousAt (fun t => 1) ↑x`. - -- This is true because constant functions are continuous everywhere. We use `fun_prop` to - -- establish this. - · fun_prop - -- `case refine_2`: The goal is `⊢ ContinuousAt (HMul.hMul kB) ↑x`. - -- This is true because multiplication by a constant is continuous everywhere. - -- We use `fun_prop` to establish this. - · fun_prop - -- `case refine_3`: The goal is `⊢ kB * ↑x ≠ 0`. - -- We have the hypothesis `h_x_ne_zero : (x : ℝ) ≠ 0` derived from `ne_of_gt h_x_pos`; - -- which means: "Given a and b, if a > b, then a ≠ b" - and since we have `0 < x`, - -- we conclude `x ≠ 0`. - · have h_x_ne_zero : (x : ℝ) ≠ 0 := by - exact (ne_of_gt h_x_pos) - exact mul_ne_zero kB_ne_zero h_x_ne_zero - -/-- Helper lemma for `Temperature`: - -Continuity at a positive point for the same formula on `ℝ≥0`. --/ -private lemma ofβ_realExpr_continuousAt_nnreal (x : ℝ≥0) (h_x_pos : 0 < x) : - ContinuousAt (fun (b : ℝ≥0) => (1 : ℝ) / (kB * b)) x := by - -- We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`. - -- This is the same as the function in the goal, but we give it a name for clarity. - let f : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (1 : ℝ) / (kB * b) - -- We define `g : ℝ → ℝ` as `g (t : ℝ) := (1 : ℝ) / (kB * t)`. - -- This is the same formula as `f`, but defined on `ℝ`. - let g : ℝ → ℝ := fun (t : ℝ) => (1 : ℝ) / (kB * t) - -- We define `h : ℝ≥0 → ℝ` as `h (b : ℝ≥0) := (b : ℝ)`. - -- This is the coercion from `ℝ≥0` to `ℝ`. - let h : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (b : ℝ) - -- We then prove that `f = g ∘ h` by simplifying both sides and showing they are equal. - -- This is done by `rfl`, since both sides are definitionally equal. - have f_eq_g_comp_h : f = (g ∘ h) := by - rfl - -- We then prove that `g` is continuous at `x : ℝ` using the previous lemma `ofβ_realExpr_continuousAt_real x h_x_pos`, resulting in the hypothesis `h_continuousAt_real`. - have h_continuousAt_real : ContinuousAt g (x : ℝ) := ofβ_realExpr_continuousAt_real x h_x_pos - -- We also prove that `h` is continuous at `x : ℝ≥0` using `continuous_subtype_val.continuousAt`, - -- which states that the coercion from a subtype to its parent type is continuous at every point, - -- resulting in the hypothesis `h_continuousAt_subtype`. - have h_continuousAt_subtype : ContinuousAt h (x : ℝ≥0) := continuous_subtype_val.continuousAt - -- Finally, we conclude that `f` is continuous at `x` by using the composition of - -- continuous functions: `h_continuousAt_real.comp h_continuousAt_subtype`. QED. - exact h_continuousAt_real.comp h_continuousAt_subtype - -/-- Helper lemma for `Temperature`: - -Continuity at a positive point for the `ℝ≥0`-valued `val` component of `ofβ`. --/ -private lemma ofβ_val_continuousAt (x : ℝ≥0) (h_x_pos : 0 < x) : - ContinuousAt (fun (b : ℝ≥0) => ((ofβ b).val : ℝ≥0)) x := by - -- We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`, - -- which is the real-valued formula used by `ofβ`. - let f : ℝ≥0 → ℝ := fun b => (1 : ℝ) / (kB * b) - -- Then, we prove that `f` is continuous at `x` using the previous lemma - -- `ofβ_realExpr_continuousAt_nnreal x h_x_pos`, - -- resulting in the hypothesis `h_f_continuousAt`. - have h_continuousAt_nnreal : ContinuousAt f x := by - exact ofβ_realExpr_continuousAt_nnreal x h_x_pos - -- Next, we prove that `f` is nonnegative for all `b : ℝ≥0` using the lemma `ofβ_real_nonneg b`, - -- resulting in the hypothesis `h_f_nonneg`. - have h_f_nonneg : ∀ b : ℝ≥0, 0 ≤ f (b : ℝ≥0) := by - intro b - exact ofβ_real_nonneg b - -- We then define `g : ℝ≥0 → ℝ≥0` as `g (b : ℝ≥0) := ⟨f b, h_f_nonneg b⟩`, - -- which is the same formula as `f` but with codomain restricted to `ℝ≥0`. - let g : ℝ≥0 → ℝ≥0 := fun b => (⟨f b, h_f_nonneg b⟩ : ℝ≥0) - -- We prove that `g` is continuous at `x` by using the fact that if a real-valued function - -- is continuous, then its codomain-restricted version is also continuous. - -- This gives us the hypothesis `h_g_continuousAt`. - have h_g_continuousAt : ContinuousAt g x := by - exact h_continuousAt_nnreal.codRestrict h_f_nonneg - -- Finally, we conclude that the `val` component of `ofβ` is continuous at `x` - -- by using the hypothesis `h_g_continuousAt`, - -- since `g` is definitionally equal to the function we want to prove continuous. QED. - exact h_g_continuousAt - -/-- Helper lemma for `Temperature`: - -The topology on `Temperature` is induced by the coercion to `ℝ≥0`. --/ -private lemma temperature_val_isInducing : - Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0)) := by - -- This is immediate from the topology instance definition, - -- which is exactly `induced` by this coercion map. - -- Therefore the witness is `⟨rfl⟩`. - exact ⟨rfl⟩ - -/-- Helper lemma for `Temperature`: - -Continuity of `ofβ` at every strictly positive input. --/ -private lemma ofβ_continuousAt_of_pos (x : ℝ≥0) (h_x_pos : 0 < x) : - ContinuousAt (ofβ : ℝ≥0 → Temperature) x := by - -- We refine the goal using `temperature_val_isInducing.continuousAt_iff`, - -- which states that continuity of a function into `Temperature` can be checked - -- by continuity of its composition with the coercion to `ℝ≥0`. - -- The goal is now `⊢ ContinuousAt ((fun T => T.val) ∘ ofβ) x`. - refine (temperature_val_isInducing.continuousAt_iff).mpr ?_ - -- This is exactly the content of the previous lemma `ofβ_val_continuousAt x h_x_pos`, - -- so we apply that to conclude. QED. - exact ofβ_val_continuousAt x h_x_pos - -/-- Lemma for `Temperature`: - -The function `ofβ` is continuous on the interval `(0, ∞)`. --/ -lemma ofβ_continuousOn : ContinuousOn (ofβ : ℝ≥0 → Temperature) (Set.Ioi 0) := by - -- We refine the goal using `continuousOn_of_forall_continuousAt`, - -- which reduces continuity on a set to continuity at every point in that set. - -- The goal is now `⊢ ∀ x ∈ Set.Ioi 0, ContinuousAt ofβ x`. - refine continuousOn_of_forall_continuousAt ?_ - -- We introduce `x : ℝ≥0` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. - intro x h_x_in_set - -- From `h_x_in_set`, we derive `h_x_pos : 0 < x` by: - have h_x_pos : 0 < x := by - -- Simplifying the definition of `Set.Ioi 0`, which states that `x ∈ Set.Ioi 0` means `0 < x`. - simp at h_x_in_set - -- Extracting the strict inequality `0 < x` from this definition. - exact h_x_in_set - -- Given `x : ℝ≥0` and `h_x_pos : 0 < x`, - -- we can prove the goal with `ofβ_continuousAt_of_pos x h_x_pos`. QED. - exact ofβ_continuousAt_of_pos x h_x_pos - -/-- Lemma for `Temperature`: - -The function `ofβ` is differentiable on the interval `(0, ∞)`. --/ -lemma ofβ_differentiableOn : - DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0) := by - -- We refine the goal using `DifferentiableOn.congr`, which allows us to prove differentiability - -- by showing that the function is equal to a simpler function that we can easily differentiate. - -- We now have two cases: - refine DifferentiableOn.congr (f := fun (x : ℝ) => (1 : ℝ) / (kB * x)) ?_ ?_ - -- `case refine_1` : The goal is `⊢ DifferentiableOn ℝ (fun x => 1 / (kB * x)) (Set.Ioi 0)`. - -- We further refine this using `DifferentiableOn.fun_div`, which requires us - -- to prove differentiability of the numerator and denominator separately, - -- and that the denominator is nonzero on the set: - · refine DifferentiableOn.fun_div ?_ ?_ ?_ - -- `case refine_1.refine_1` : The goal is `⊢ DifferentiableOn ℝ (fun x => 1) (Set.Ioi 0)`. - -- This is true because constant functions are differentiable everywhere. - -- We use `fun_prop` to establish this. - · fun_prop - -- `case refine_1.refine_2` : The goal is `⊢ DifferentiableOn ℝ (HMul.hMul kB) (Set.Ioi 0)`. - -- This is true because multiplication by a constant is differentiable everywhere. - -- We use `fun_prop` to establish this. - · fun_prop - -- `case refine_1.refine_3` : The goal is `⊢ ∀ x ∈ Set.Ioi 0, kB * x ≠ 0`. - -- We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. - -- The goal is now `⊢ kB * x ≠ 0`. - · intro x h_x_in_set - -- We derive `h_x_ne_zero : x ≠ 0` from `h_x_in_set` by noting that - -- if `x` is strictly greater than `0`, then it cannot be equal to `0`. - have h_x_ne_zero : x ≠ 0 := by - exact ne_of_gt h_x_in_set - -- We then apply `mul_ne_zero` to conclude that `kB * x` is nonzero. - apply mul_ne_zero - -- The first factor `kB` is nonzero by `kB_ne_zero`. - · exact kB_ne_zero - -- The second factor `x` is nonzero by `h_x_ne_zero`. - -- This completes the proof of this case. QED for `refine_1.refine_3`. - -- QED for `refine_1`. - · exact h_x_ne_zero - -- `case refine_2` : The goal is - -- `⊢ ∀ x ∈ Set.Ioi 0, ↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. - -- We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. - -- The goal is now `↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. - · intro x h_x_in_set - -- We derive `h_x_pos : 0 < x` from `h_x_in_set` by simplifying the definition of `Set.Ioi 0` - -- to extract the strict inequality `0 < x`. - have h_x_pos : 0 < x := by - simp at h_x_in_set - exact h_x_in_set - -- We also derive `h_x_nonneg : 0 ≤ x` from `h_x_pos` by noting that - -- if `x` is strictly greater than `0`, then it can be considered as - -- "greater than or equal to `0`" as well (since `0 < x` implies `0 ≤ x`). - have h_x_nonneg : 0 ≤ x := by - simpa using h_x_pos.le - -- We then simplify the goal using `simp` to get a new goal - -- that is a disjunction: `⊢ 0 ≤ x ∨ kB = 0`. - simp - -- We only have to prove the left disjunct `0 ≤ x` since `kB` is nonzero by `kB_ne_zero` - -- (thus the right disjunct is false). - left - -- We have already established `h_x_nonneg : 0 ≤ x`, so we can conclude this case - -- by left disjunction and using `h_x_nonneg`. - -- This completes the proof of this case. QED for `refine_2`. - -- All cases have been proven. QED. - simp [h_x_nonneg] - -/-! ### Convergence -/ - -open Filter Topology - -/-- Lemma for `Temperature`: - -The function `ofβ` produces strictly positive real-valued temperatures -for sufficiently large inverse temperature β. --/ -lemma eventually_pos_ofβ : ∀ᶠ b : ℝ≥0 in atTop, ((Temperature.ofβ b : Temperature) : ℝ) > 0 := by - -- We start by proving that for sufficiently large `b : ℝ≥0`, - -- we have `1 ≤ b` using `Filter.eventually_ge_atTop 1`, - -- which states that eventually, all elements of the filter - -- at infinity are greater than or equal to `1`. - -- This gives us the hypothesis `h_eventually_b_ge_one`. - have h_eventually_b_ge_one : ∀ᶠ b : ℝ≥0 in atTop, (1 : ℝ≥0) ≤ b := Filter.eventually_ge_atTop 1 - -- We then refine the goal using `h_eventually_b_ge_one.mono`, - -- which allows us to prove the desired property for all `b` that satisfy `1 ≤ b`. - -- The new goal is now `⊢ ∀ (x : ℝ≥0), 1 ≤ x → (ofβ x).toReal > 0`. - refine h_eventually_b_ge_one.mono ?_ - -- We introduce `b : ℝ≥0` and the hypothesis `h_b_ge_one : 1 ≤ b` from the goal. - -- The goal is now `⊢ (ofβ b).toReal > 0`. - intro b h_b_ge_one - -- We derive `h_b_pos : 0 < (b : ℝ)` using `zero_lt_one.trans_le h_b_ge_one`, - -- which states that if `0 < 1` and `1 ≤ b`, then `0 < b`. - have h_b_pos : 0 < (b : ℝ) := by - exact zero_lt_one.trans_le h_b_ge_one - -- We derive `h_denominator_pos : 0 < kB * (b : ℝ)` using `mul_pos kB_pos h_b_pos`, - -- which states that if `kB` is positive (proven by `kB_pos`) - -- and `b` is positive (proven by `h_b_pos`), then their product is positive. - have h_denominator_pos : 0 < kB * (b : ℝ) := by - exact mul_pos kB_pos h_b_pos - -- We derive `h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ))` - -- using `one_div_pos.mpr h_denominator_pos`, which states that if the denominator is positive, - -- then the reciprocal is also positive. - have h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ)) := one_div_pos.mpr h_denominator_pos - -- We change the goal of `⊢ (ofβ b).toReal > 0` to its equivalent form - -- `⊢ (fun b => 1 / (kB * ↑b)) b > 0`. - change - (λ (b : ℝ≥0) => (1 : ℝ) / (kB * b)) b > 0 - -- We can apply `h_quotient_pos` to conclude that the goal is true, since `h_quotient_pos` states - -- that the expression `1 / (kB * (b : ℝ))` is positive, which is exactly what we need to show. - -- QED. - exact h_quotient_pos - -/-- Helper lemma for `Temperature`: - -Positivity of the epsilon-delta bound construction. --/ -private lemma tendsto_const_inv_mul_bound_pos (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : - 0 < (1 / (a * ε)) + 1 := by - -- We derive `h_reciprocal_pos : 0 < (1 / (a * ε))` to show that the first term in the sum - -- is positive, which will allow us to conclude that the entire sum is positive. - have h_reciprocal_pos : 0 < (1 / (a * ε)) := by - -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, - -- which states that the product of two positive numbers is positive - -- (proof of `a` and `ε` being positive are given by `h_a_pos` and `h_ε_pos`). - have h_product_pos : 0 < a * ε := by - exact mul_pos h_a_pos h_ε_pos - -- We then apply `one_div_pos.mpr h_product_pos` to conclude that `1 / (a * ε)` is positive, - -- since `h_product_pos` states that the denominator is positive. QED for this part. - exact one_div_pos.mpr h_product_pos - -- Finally, we apply `add_pos` to `h_reciprocal_pos` and `zero_lt_one` to conclude that the sum - -- `(1 / (a * ε)) + 1` is positive, since both terms are positive. QED. - exact add_pos h_reciprocal_pos zero_lt_one - -/-- Helper lemma for `Temperature`: - -Product positivity via transitivity of ordering. --/ -private lemma tendsto_const_inv_mul_product_pos_of_le (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) - (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : - 0 < a * b := by - -- We derive `h_b_pos : 0 < b` using `lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b`, - -- which states that if `b_lower_bound` is positive and `b_lower_bound ≤ b`, - -- then `b` is also positive. - have h_b_pos : 0 < b := lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b - -- We then apply `mul_pos` to `h_a_pos` and `h_b_pos` to conclude that the product - -- `a * b` is positive. QED. - exact mul_pos h_a_pos h_b_pos - -/-- Helper lemma for `Temperature`: - -Antitonicity of reciprocal function with constant multiplier. --/ -private lemma tendsto_const_inv_mul_reciprocal_antitone (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) - (h_product_b_lower_bound_pos : 0 < a * b_lower_bound) - (h_b_lower_bound_le_b : b_lower_bound ≤ b) : - (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by - -- We derive `h_denom_le : (a * b_lower_bound) ≤ (a * b)` - -- using `mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos)`, which states that - -- if `b_lower_bound ≤ b` and `a` is non-negative, then multiplying both sides by `a` preserves the - -- inequality, giving us `a * b_lower_bound ≤ a * b`. - have h_denom_le : (a * b_lower_bound) ≤ (a * b) := by - exact mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos) - -- Then we apply `one_div_le_one_div_of_le` to `h_product_b_lower_bound_pos` and `h_denom_le` - -- to conclude that the reciprocal of the larger denominator is less than or equal to the - -- reciprocal of the smaller denominator, which establishes the antitonicity. QED. - exact one_div_le_one_div_of_le h_product_b_lower_bound_pos h_denom_le - -/-- Helper lemma for `Temperature`: - -Evaluating the function at the constructed bound yields a value less than `ε`. --/ -private lemma tendsto_const_inv_mul_at_bound_lt_epsilon (a ε : ℝ) (h_a_pos : 0 < a) - (h_ε_pos : 0 < ε) : - (1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε := by - -- We first simplify the expression by performing field simplification with `field_simp` - -- to rewrite the goal into `⊢ 1 < 1 + a * ε`. - field_simp - -- We then simplify further using `simp` to reduce the goal to `⊢ 0 < a * ε`. - simp - -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, - -- which states that the product of two positive numbers is positive. - have h_product_pos : 0 < a * ε := by - exact mul_pos h_a_pos h_ε_pos - -- Finally, we conclude that `⊢ 0 < a * ε` is true by `h_product_pos`. QED. - exact h_product_pos - - -/-- Helper lemma for `Temperature`: - -Conversion from nonnegative inequality to metric space distance. --/ -private lemma tendsto_const_inv_mul_nonneg_to_dist (x ε : ℝ) (h_x_nonneg : 0 ≤ x) - (h_x_lt_ε : x < ε) : - dist x 0 < ε := by - -- We rewrite the goal `⊢ dist x 0 < ε` using `Real.dist_eq` to express the distance - -- in terms of absolute value (`dist x 0` is equal to `|x - 0|`), - -- and use `sub_zero` to simplify this to `⊢ |x| < ε`. - rw [Real.dist_eq, sub_zero] - -- We derive `h_abs_lt : |x| < ε`, by rewriting `|x|` as `x` using `abs_of_nonneg h_x_nonneg`, - -- which states that if `x` is nonnegative, then `|x|` is equal to `x`. - -- Then we apply `h_x_lt_ε` to conclude that `|x| < ε` is true. - have h_abs_lt : |x| < ε := by - rw [abs_of_nonneg h_x_nonneg] - exact h_x_lt_ε - -- Finally, we conclude that `⊢ |x| < ε` is true by `h_abs_lt`. QED. - exact h_abs_lt - -/-- Helper lemma for `Temperature`: - -Given a lower bound on `b` that ensures the function value is less than `ε`, -we can conclude that for any `b` greater than or equal to that lower bound, -the function value is nonnegative and less than `ε`. --/ -private lemma tendsto_const_inv_mul_nonneg_and_lt_of_bound (a ε b_lower_bound b : ℝ) - (h_a_pos : 0 < a)(h_b_lower_bound_pos : 0 < b_lower_bound) - (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : - 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := by - -- We derive `h_prod_lower_bound_pos : 0 < a * b_lower_bound` - -- using `mul_pos h_a_pos h_b_lower_bound_pos`, which states that the product of - -- two positive numbers is positive (proof of `a` and `b_lower_bound` being positive are given by - -- `h_a_pos` and `h_b_lower_bound_pos`). - have h_prod_lower_pos : 0 < a * b_lower_bound := by - exact mul_pos h_a_pos h_b_lower_bound_pos - -- We then derive `h_prod_pos : 0 < a * b` using the previous lemma - -- `tendsto_const_inv_mul_product_pos_of_le`, which states that if `b` is greater than or equal - -- to a positive lower bound, then the product `a * b` is also positive. - have h_prod_pos : 0 < a * b := by - exact tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b - h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b - -- We then derive `h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)` - -- using the previous lemma `tendsto_const_inv_mul_reciprocal_antitone`, - -- which states that the reciprocal function is antitone. - have h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by - exact tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b - h_a_pos h_prod_lower_pos h_b_lower_bound_le_b - -- We then derive `h_lt : (1 : ℝ) / (a * b) < ε` using `lt_of_le_of_lt h_rec_le h_at_bound_lt`, - -- which states that if `1 / (a * b)` is less than or equal to `1 / (a * b_lower_bound)` - -- and `1 / (a * b_lower_bound)` is less than `ε`, then `1 / (a * b)` is also less than `ε`. - have h_lt : (1 : ℝ) / (a * b) < ε := by - exact lt_of_le_of_lt h_rec_le h_at_bound_lt - -- We then derive `h_nonneg : 0 ≤ (1 : ℝ) / (a * b)` - -- using `div_nonneg zero_le_one (le_of_lt h_prod_pos)`, - -- which states that the reciprocal of a positive number is nonnegative. - have h_nonneg : 0 ≤ (1 : ℝ) / (a * b) := by - exact div_nonneg zero_le_one (le_of_lt h_prod_pos) - -- Finally, we conclude that both `0 ≤ (1 : ℝ) / (a * b)` and `(1 : ℝ) / (a * b) < ε` hold by - -- the proofs of `h_nonneg` and `h_lt`. QED. - exact ⟨h_nonneg, h_lt⟩ - -/-- Helper lemma for `Temperature`: - -Given a lower bound on `b` that ensures the function value is less than `ε`, -we can conclude that for any `b` greater than or equal to that lower bound, -the distance from the function value to `0` is less than `ε`. --/ -private lemma tendsto_const_inv_mul_dist_lt_of_bound (a ε b_lower_bound b : ℝ) (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : dist ((1 : ℝ) / (a * b)) (0 : ℝ) < ε := by - -- We derive `h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` - -- using the previous lemma `tendsto_const_inv_mul_nonneg_and_lt_of_bound`, - -- which states that for any `b` greater than or equal to the lower bound, - -- the function value is nonnegative and less than `ε`. - have h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := - tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b - h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt - -- Finally, we apply the previous lemma `tendsto_const_inv_mul_nonneg_to_dist` to conclude that - -- the distance from the function value to `0` is less than `ε`, since we have established that - -- the function value is nonnegative and less than `ε`. QED. - exact tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε - h_nonneg_and_lt.left h_nonneg_and_lt.right - -/-- Helper lemma for `Temperature`: - -As `b` tends to infinity, the distance from the function value `1 / (a * b)` to `0` -becomes less than any positive `ε` for sufficiently large `b`. - -(TODO) --/ -private lemma tendsto_const_inv_mul_atTop_eventually_dist_lt (a : ℝ) (h_a_pos : 0 < a) (ε : ℝ) - (h_ε_pos : 0 < ε) : ∀ᶠ b : - ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε := by - -- We construct a real number `B_real` defined as `(1 / (a * ε)) + 1`, - -- which serves as a candidate lower bound for `b` to ensure that the function value - -- is less than `ε`. - let B_real : ℝ := (1 / (a * ε)) + 1 - -- We then derive `h_B_real_pos : 0 < B_real` using the previous lemma - -- `tendsto_const_inv_mul_bound_pos`, which states that the constructed bound is positive. - have h_B_real_pos : 0 < B_real := by - exact tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos - -- We then define a nonnegative real number `B_nnreal` by taking the nonnegative part of - -- `B_real`, ensuring that it is still positive. - let B_nnreal : ℝ≥0 := ⟨B_real, le_of_lt h_B_real_pos⟩ - -- We then derive `h_B_nnreal_pos : 0 < (B_nnreal : ℝ)` from `h_B_real_pos` - -- by noting that the coercion of `B_nnreal` to `ℝ` is exactly `B_real`, which is positive. QED. - have h_B_nnreal_pos : 0 < B_nnreal:= by - exact h_B_real_pos - -- We then refine the goal using `Filter.eventually_ge_atTop B_nnreal`, - -- which states that eventually, all elements of the filter at infinity are greater than or equal - -- to `B_nnreal`. The goal is now `⊢ ∀ (x : ℝ≥0), B_nnreal ≤ x → dist (1 / (a * ↑x)) 0 < ε`. - refine (Filter.eventually_ge_atTop B_nnreal).mono ?_ - -- We introduce `b : ℝ≥0` and the hypothesis `h_B_nnreal_le_b : B_nnreal ≤ b` from the goal. - --The goal is now `⊢ dist (1 / (a * ↑b)) 0 < ε`. - intro b h_B_nnreal_le_b - -- We derive `h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε` using the previous lemma - -- `tendsto_const_inv_mul_at_bound_lt_epsilon`, which states that evaluating the function - -- at the constructed bound yields a value less than `ε`. - have h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε := by - exact tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos - -- Finally, we apply `tendsto_const_inv_mul_dist_lt_of_bound` - -- to conclude that the distance from the function value to `0` is less than `ε` - -- for any `b` greater than or equal to the constructed bound. QED. - exact tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) - h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt - -/-- Helper lemma for `Temperature`: - -As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` -in the sense of the metric space distance. --/ -private lemma tendsto_const_inv_mul_atTop (a : ℝ) (h_a_pos : 0 < a) : - Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by - -- We refine the goal using `Metric.tendsto_nhds.mpr`, - -- which allows us to prove the convergence by showing that for every positive `ε`, - -- the function values are eventually within `ε` of `0`. - -- The new goal is now `⊢ ∀ ε > 0, ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. - refine Metric.tendsto_nhds.mpr ?_ - -- We introduce `ε : ℝ` and the hypothesis `h_ε_pos : 0 < ε` from the goal. - -- The goal is now `⊢ ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. - intro ε h_ε_pos - -- We apply the previous lemma `tendsto_const_inv_mul_atTop_eventually_dist_lt` - -- to conclude that for sufficiently large `b`, the distance from the function value to `0` - -- is less than `ε`. QED. - exact tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos - -/-- Lemma for `Temperature`: - -As the inverse temperature `β` tends to infinity, -the real-valued representation of the temperature `ofβ β` tends to `0` -in the sense of the metric space distance. --/ -lemma tendsto_toReal_ofβ_atTop : - Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ)) := by - -- We apply the previous lemma `tendsto_const_inv_mul_atTop` - -- with `a` set to `kB` and `h_a_pos` set to `kB_pos`, - -- which states that as `b` tends to infinity, the function value `1 / (kB * b)` tends to `0`. - -- Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. - exact tendsto_const_inv_mul_atTop kB kB_pos - -/-- Lemma for `Temperature`: - -As the inverse temperature `β` tends to infinity, -the real-valued representation of the temperature `ofβ β` -tends to `0` from above (within the interval `(0, ∞)`). --/ -lemma tendsto_ofβ_atTop : - Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) - atTop (nhdsWithin 0 (Set.Ioi 0)) := by - -- We derive `h_tendsto_nhds_zero` from - -- `tendsto_toReal_ofβ_atTop`, which states that as `β` - -- tends to infinity, the real-valued temperature - -- tends to `0` in the nhds sense. - have h_tendsto_nhds_zero := tendsto_toReal_ofβ_atTop - -- We derive `h_tendsto_principal_Ioi` which states that - -- as `β` tends to infinity, the real-valued temperature - -- eventually lies in the interval `(0, ∞)`, using - -- `tendsto_principal.mpr` and `eventually_pos_ofβ`. - have h_tendsto_principal_Ioi : - Tendsto (fun b : ℝ≥0 => - (Temperature.ofβ b : ℝ)) - atTop (𝓟 (Set.Ioi (0 : ℝ))) := - tendsto_principal.mpr - (by simpa using Temperature.eventually_pos_ofβ) - -- We combine `h_tendsto_nhds_zero` and - -- `h_tendsto_principal_Ioi` using `tendsto_inf.mpr` to - -- conclude that the function tends to `0` within the - -- infimum filter `nhds 0 ⊓ 𝓟 (Set.Ioi 0)`. - have h_tendsto_inf : - Tendsto (fun b : ℝ≥0 => - (Temperature.ofβ b : ℝ)) - atTop - ((nhds (0 : ℝ)) ⊓ 𝓟 (Set.Ioi (0 : ℝ))) := - tendsto_inf.mpr - ⟨h_tendsto_nhds_zero, h_tendsto_principal_Ioi⟩ - -- Since `nhdsWithin 0 (Set.Ioi 0)` is defined as - -- `nhds 0 ⊓ 𝓟 (Set.Ioi 0)`, the conclusion follows - -- directly from `h_tendsto_inf` by simplification. - -- QED. - simpa [nhdsWithin] using h_tendsto_inf - /-! ### Conversion to and from `ℝ≥0` -/ -open Constants - /-- Simplification function for `Temperature`: Build a temperature from a nonnegative real number. @@ -927,215 +379,4 @@ lemma ofRealNonneg_val {t : ℝ} (h_zero_le_t : 0 ≤ t) : -- Both sides are definitionally equal by the definition of `ofRealNonneg`. QED. rfl -/-! ### Calculus relating T and β -/ - -open Set -open scoped ENNReal - -/-- Function for `Temperature`: - -Map a real number `t` to the inverse temperature `β` corresponding to -the temperature `Real.toNNReal t` (`max t 0`), returned as a real number. - -Note: - -1. Why `ℝ` instead of `ℝ≥0`, if `β` is of type `ℝ≥0`? --/ -noncomputable def βFromReal (t : ℝ) : ℝ := ((Temperature.ofNNReal (Real.toNNReal t)).β) - -/-- Lemma for `Temperature`: - -Explicit closed-form for `βFromReal t` when `t > 0`: `βFromReal t = 1 / (kB * t)`. --/ -lemma β_fun_T_formula (t : ℝ) (h_t_pos : 0 < t) : - βFromReal t = (1 : ℝ) / (kB * t) := by - -- We derive `h_t_nonneg : 0 ≤ t` from `h_t_pos` by weakening strict - -- inequality to non-strict inequality. - have h_t_nonneg : (0 : ℝ) ≤ t := h_t_pos.le - -- We derive `h_beta_formula` which states that the explicit formula - -- for `β` applied to `Real.toNNReal t` equals `1 / (kB * t)`, - -- by simplifying using the definitions of `β`, `ofNNReal`, `toReal`, - -- and the fact that `Real.toNNReal t = t` when `t ≥ 0`. - have h_beta_formula : - ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = (1 : ℝ) / (kB * t) := by - simp [Temperature.β, Temperature.ofNNReal, Temperature.toReal, - Real.toNNReal_of_nonneg h_t_nonneg, one_div, mul_comm] - -- We conclude by simplifying the definition of `βFromReal` and - -- applying `h_beta_formula`. QED. - simpa [βFromReal] using h_beta_formula - -/-- Lemma for `Temperature`: - -On the interval `(0, ∞)`, `βFromReal t` equals `1 / (kB * t)`. --/ -lemma β_fun_T_eq_on_Ioi : EqOn βFromReal (fun t : ℝ => (1 : ℝ) / (kB * t)) (Set.Ioi 0) := by - -- We introduce `t : ℝ` and the hypothesis - -- `h_t_pos : t ∈ Set.Ioi 0` (i.e. `0 < t`) from the goal. - intro t h_t_pos - -- We simplify `h_t_pos` to extract the inequality `0 < t`. - simp at h_t_pos - -- We apply `β_fun_T_formula t h_t_pos` to conclude that - -- `βFromReal t = 1 / (kB * t)`. QED. - exact β_fun_T_formula t h_t_pos - -/-- Lemma for `Temperature`: - -The function `βFromReal` has derivative `-1 / (kB * T²)` within the -interval `(0, ∞)` at the point `T.val`, when `T` is strictly positive. --/ -lemma deriv_β_wrt_T (T : Temperature) (h_T_pos : 0 < T.val) : HasDerivWithinAt βFromReal - (-1 / (kB * (T.val : ℝ)^2)) (Set.Ioi 0) (T.val : ℝ) := by - -- We define `f : ℝ → ℝ` as the explicit formula - -- `f t = 1 / (kB * t)`, which is the closed form of - -- `βFromReal` on `(0, ∞)`. - let f : ℝ → ℝ := fun t => (1 : ℝ) / (kB * t) - -- We derive `h_eq_on : EqOn βFromReal f (Set.Ioi 0)` - -- using `β_fun_T_eq_on_Ioi`, which states that - -- `βFromReal` and `f` agree on `(0, ∞)`. - have h_eq_on : EqOn βFromReal f (Set.Ioi 0) := - β_fun_T_eq_on_Ioi - -- We derive `h_T_ne_zero : (T.val : ℝ) ≠ 0` from - -- `h_T_pos` using `ne_of_gt`, since a strictly positive - -- number is nonzero. - have h_T_ne_zero : (T.val : ℝ) ≠ 0 := - ne_of_gt h_T_pos - -- We derive `h_f_def` which rewrites `f` in terms of - -- inverses: `f = fun t => kB⁻¹ * t⁻¹`, by case-splitting - -- on whether `t = 0` and simplifying. - have h_f_def : - f = fun t : ℝ => (kB)⁻¹ * t⁻¹ := by - funext t - -- We case-split on whether `t = 0`. - by_cases h_t_eq_zero : t = 0 - -- If `t = 0`, both sides simplify to `0`. - · simp [f, h_t_eq_zero] - -- If `t ≠ 0`, we simplify and apply `ring`. QED. - · simp [f, one_div, *] at * - ring - -- We derive `h_inv` which states that the derivative of - -- `t⁻¹` at `T.val` is `-(T.val²)⁻¹`, using - -- `hasDerivAt_inv` with `h_T_ne_zero`. - have h_inv : - HasDerivAt (fun t : ℝ => t⁻¹) - (-((T.val : ℝ) ^ 2)⁻¹) (T.val : ℝ) := by - simpa using - (hasDerivAt_inv (x := (T.val : ℝ)) h_T_ne_zero) - -- We derive `h_deriv_aux` which states the derivative of - -- `kB⁻¹ * t⁻¹` at `T.val` is `kB⁻¹ * (-(T.val²)⁻¹)`, - -- by applying the constant-multiple rule to `h_inv`. - have h_deriv_aux : - HasDerivAt (fun t : ℝ => (kB)⁻¹ * t⁻¹) - ((kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹)) - (T.val : ℝ) := - h_inv.const_mul ((kB)⁻¹) - -- We derive `h_pow_simp` which simplifies the derivative - -- expression `kB⁻¹ * (-(T.val²)⁻¹)` to the target form - -- `-1 / (kB * T.val²)`, using algebraic manipulations. - have h_pow_simp : - (kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹) = - -1 / (kB * (T.val : ℝ)^2) := by - calc - (kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹) - = -((kB)⁻¹ * ((T.val : ℝ) ^ 2)⁻¹) := by - ring - _ = -(1 / kB * (1 / (T.val : ℝ) ^ 2)) := by - simp [one_div] - _ = -1 / (kB * (T.val : ℝ) ^ 2) := by - rw [one_div] - field_simp [pow_two, mul_comm, - mul_left_comm, mul_assoc, - kB_ne_zero, h_T_ne_zero] - -- We derive `h_deriv_f` which states that `f` has - -- derivative `-1 / (kB * T.val²)` at `T.val`, by - -- combining `h_f_def`, `h_pow_simp`, and `h_deriv_aux`. - have h_deriv_f : - HasDerivAt f - (-1 / (kB * (T.val : ℝ)^2)) - (T.val : ℝ) := by - simpa [h_f_def, h_pow_simp] using h_deriv_aux - -- We derive `h_mem : (T.val : ℝ) ∈ Set.Ioi 0` from - -- `h_T_pos`, confirming that the evaluation point lies - -- in the domain. - have h_mem : (T.val : ℝ) ∈ Set.Ioi (0 : ℝ) := - h_T_pos - -- We conclude by converting `h_deriv_f` to a - -- `HasDerivWithinAt` and applying `congr` with `h_eq_on` - -- to replace `f` by `βFromReal` on the set. QED. - exact (h_deriv_f.hasDerivWithinAt).congr - h_eq_on (h_eq_on h_mem) - -/-- Lemma for `Temperature`: - -Chain rule for `β(T)`: if `F` has derivative `F'` at `β(T)` within -`(0, ∞)`, then the composition `t ↦ F(βFromReal(t))` has derivative -`F' * (-1 / (kB * T²))` within `(0, ∞)` at `T.val`. --/ -lemma chain_rule_T_β {F : ℝ → ℝ} {F' : ℝ} - (T : Temperature) (h_T_pos : 0 < T.val) - (h_F_deriv : HasDerivWithinAt F F' (Set.Ioi 0) (T.β : ℝ)) : - HasDerivWithinAt (fun t : ℝ => F (βFromReal t)) - (F' * (-1 / (kB * (T.val : ℝ)^2))) - (Set.Ioi 0) (T.val : ℝ) := by - -- We derive `h_β_deriv` from `deriv_β_wrt_T`, which - -- gives the derivative of `βFromReal` at `T.val`. - have h_β_deriv := - deriv_β_wrt_T (T := T) h_T_pos - -- We derive `h_maps_to` which states that `βFromReal` - -- maps `(0, ∞)` into `(0, ∞)`, i.e. positive inputs - -- produce positive outputs. - have h_maps_to : - Set.MapsTo βFromReal (Set.Ioi 0) (Set.Ioi 0) := by - -- We introduce `t : ℝ` and the hypothesis - -- `h_t_pos : t ∈ Set.Ioi 0` (i.e. `0 < t`). - intro t h_t_pos - -- We derive `h_kB_mul_t_pos : 0 < kB * t` using - -- `mul_pos kB_pos h_t_pos`. - have h_kB_mul_t_pos : 0 < kB * t := - mul_pos kB_pos h_t_pos - -- We derive `h_quotient_pos : 0 < 1 / (kB * t)` using - -- `one_div_pos.mpr h_kB_mul_t_pos`. - have h_quotient_pos : 0 < (1 : ℝ) / (kB * t) := - one_div_pos.mpr h_kB_mul_t_pos - -- We derive `h_βFromReal_eq` which states that - -- `βFromReal t = 1 / (kB * t)` on `(0, ∞)`. - have h_βFromReal_eq : - βFromReal t = (1 : ℝ) / (kB * t) := - β_fun_T_eq_on_Ioi h_t_pos - -- We conclude by rewriting `βFromReal t` with - -- `h_βFromReal_eq` and applying `h_quotient_pos`. QED. - simpa [h_βFromReal_eq] using h_quotient_pos - -- We derive `h_β_at_T` which states that - -- `βFromReal (T.val : ℝ) = (T.β : ℝ)`, i.e. the - -- explicit formula agrees with the definition of `β`. - have h_β_at_T : - βFromReal (T.val : ℝ) = (T.β : ℝ) := by - -- We derive `h_T_pos_real : 0 < (T.val : ℝ)` from - -- `h_T_pos`. - have h_T_pos_real : 0 < (T.val : ℝ) := h_T_pos - -- We derive `h_βFromReal_eq_at_T` from - -- `β_fun_T_eq_on_Ioi h_T_pos_real`. - have h_βFromReal_eq_at_T := - β_fun_T_eq_on_Ioi h_T_pos_real - -- We conclude by simplifying with the definitions of - -- `β` and `toReal`. QED. - simpa [Temperature.β, Temperature.toReal] - using h_βFromReal_eq_at_T - -- We derive `h_F_deriv_at_βFromReal` which rewrites - -- `h_F_deriv` to use `βFromReal (T.val)` instead of - -- `(T.β : ℝ)`, using `h_β_at_T`. - have h_F_deriv_at_βFromReal : - HasDerivWithinAt F F' - (Set.Ioi 0) (βFromReal (T.val : ℝ)) := by - simpa [h_β_at_T] using h_F_deriv - -- We derive `h_composition` by applying the chain rule - -- (`HasDerivWithinAt.comp`) to compose `F` with - -- `βFromReal`, using `h_F_deriv_at_βFromReal`, - -- `h_β_deriv`, and `h_maps_to`. - have h_composition := - h_F_deriv_at_βFromReal.comp - (T.val : ℝ) h_β_deriv h_maps_to - -- We conclude by simplifying `h_composition` with - -- `mul_comm` to match the target derivative expression. - -- QED. - simpa [mul_comm] using h_composition end Temperature diff --git a/PhysLean/Thermodynamics/Temperature/Calculus.lean b/PhysLean/Thermodynamics/Temperature/Calculus.lean new file mode 100644 index 000000000..9a9d84988 --- /dev/null +++ b/PhysLean/Thermodynamics/Temperature/Calculus.lean @@ -0,0 +1,238 @@ +/- +Copyright (c) 2026 Joseph Tooby-Smith. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Trong-Nghia Be, Matteo Cipollina, Tan-Phuoc-Hung Le, Joseph Tooby-Smith +-/ +import Mathlib.Analysis.Calculus.Deriv.Inv +import PhysLean.Thermodynamics.Temperature.Basic + +/-! +# Calculus relating temperature and inverse temperature + +This file establishes the derivative of `β` with respect to temperature `T`, +and provides a chain rule for composing functions of `β` with the +temperature-to-beta map. + +## Main results + +* `Temperature.βFromReal` : Map a real `t` to `β(ofNNReal(toNNReal t))`. +* `Temperature.β_fun_T_formula` : Closed form `βFromReal t = 1 / (kB * t)` for `t > 0`. +* `Temperature.deriv_β_wrt_T` : The derivative of `βFromReal` is `-1 / (kB * T²)`. +* `Temperature.chain_rule_T_β` : Chain rule for composing through `βFromReal`. +-/ + +open NNReal + +namespace Temperature +open Constants +open Set +open scoped ENNReal + +/-- Function for `Temperature`: + +Map a real number `t` to the inverse temperature `β` corresponding to +the temperature `Real.toNNReal t` (`max t 0`), returned as a real number. + +Note: + +1. Why `ℝ` instead of `ℝ≥0`, if `β` is of type `ℝ≥0`? +-/ +noncomputable def βFromReal (t : ℝ) : ℝ := ((Temperature.ofNNReal (Real.toNNReal t)).β) + +/-- Lemma for `Temperature`: + +Explicit closed-form for `βFromReal t` when `t > 0`: `βFromReal t = 1 / (kB * t)`. +-/ +lemma β_fun_T_formula (t : ℝ) (h_t_pos : 0 < t) : + βFromReal t = (1 : ℝ) / (kB * t) := by + -- We derive `h_t_nonneg : 0 ≤ t` from `h_t_pos` by weakening strict + -- inequality to non-strict inequality. + have h_t_nonneg : (0 : ℝ) ≤ t := h_t_pos.le + -- We derive `h_beta_formula` which states that the explicit formula + -- for `β` applied to `Real.toNNReal t` equals `1 / (kB * t)`, + -- by simplifying using the definitions of `β`, `ofNNReal`, `toReal`, + -- and the fact that `Real.toNNReal t = t` when `t ≥ 0`. + have h_beta_formula : + ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = (1 : ℝ) / (kB * t) := by + simp [Temperature.β, Temperature.ofNNReal, Temperature.toReal, + Real.toNNReal_of_nonneg h_t_nonneg, one_div, mul_comm] + -- We conclude by simplifying the definition of `βFromReal` and + -- applying `h_beta_formula`. QED. + simpa [βFromReal] using h_beta_formula + +/-- Lemma for `Temperature`: + +On the interval `(0, ∞)`, `βFromReal t` equals `1 / (kB * t)`. +-/ +lemma β_fun_T_eq_on_Ioi : EqOn βFromReal (fun t : ℝ => (1 : ℝ) / (kB * t)) (Set.Ioi 0) := by + -- We introduce `t : ℝ` and the hypothesis + -- `h_t_pos : t ∈ Set.Ioi 0` (i.e. `0 < t`) from the goal. + intro t h_t_pos + -- We simplify `h_t_pos` to extract the inequality `0 < t`. + simp at h_t_pos + -- We apply `β_fun_T_formula t h_t_pos` to conclude that + -- `βFromReal t = 1 / (kB * t)`. QED. + exact β_fun_T_formula t h_t_pos + +/-- Lemma for `Temperature`: + +The function `βFromReal` has derivative `-1 / (kB * T²)` within the +interval `(0, ∞)` at the point `T.val`, when `T` is strictly positive. +-/ +lemma deriv_β_wrt_T (T : Temperature) (h_T_pos : 0 < T.val) : HasDerivWithinAt βFromReal + (-1 / (kB * (T.val : ℝ)^2)) (Set.Ioi 0) (T.val : ℝ) := by + -- We define `f : ℝ → ℝ` as the explicit formula + -- `f t = 1 / (kB * t)`, which is the closed form of + -- `βFromReal` on `(0, ∞)`. + let f : ℝ → ℝ := fun t => (1 : ℝ) / (kB * t) + -- We derive `h_eq_on : EqOn βFromReal f (Set.Ioi 0)` + -- using `β_fun_T_eq_on_Ioi`, which states that + -- `βFromReal` and `f` agree on `(0, ∞)`. + have h_eq_on : EqOn βFromReal f (Set.Ioi 0) := + β_fun_T_eq_on_Ioi + -- We derive `h_T_ne_zero : (T.val : ℝ) ≠ 0` from + -- `h_T_pos` using `ne_of_gt`, since a strictly positive + -- number is nonzero. + have h_T_ne_zero : (T.val : ℝ) ≠ 0 := + ne_of_gt h_T_pos + -- We derive `h_f_def` which rewrites `f` in terms of + -- inverses: `f = fun t => kB⁻¹ * t⁻¹`, by case-splitting + -- on whether `t = 0` and simplifying. + have h_f_def : + f = fun t : ℝ => (kB)⁻¹ * t⁻¹ := by + funext t + -- We case-split on whether `t = 0`. + by_cases h_t_eq_zero : t = 0 + -- If `t = 0`, both sides simplify to `0`. + · simp [f, h_t_eq_zero] + -- If `t ≠ 0`, we simplify and apply `ring`. QED. + · simp [f, one_div, *] at * + ring + -- We derive `h_inv` which states that the derivative of + -- `t⁻¹` at `T.val` is `-(T.val²)⁻¹`, using + -- `hasDerivAt_inv` with `h_T_ne_zero`. + have h_inv : + HasDerivAt (fun t : ℝ => t⁻¹) + (-((T.val : ℝ) ^ 2)⁻¹) (T.val : ℝ) := by + simpa using + (hasDerivAt_inv (x := (T.val : ℝ)) h_T_ne_zero) + -- We derive `h_deriv_aux` which states the derivative of + -- `kB⁻¹ * t⁻¹` at `T.val` is `kB⁻¹ * (-(T.val²)⁻¹)`, + -- by applying the constant-multiple rule to `h_inv`. + have h_deriv_aux : + HasDerivAt (fun t : ℝ => (kB)⁻¹ * t⁻¹) + ((kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹)) + (T.val : ℝ) := + h_inv.const_mul ((kB)⁻¹) + -- We derive `h_pow_simp` which simplifies the derivative + -- expression `kB⁻¹ * (-(T.val²)⁻¹)` to the target form + -- `-1 / (kB * T.val²)`, using algebraic manipulations. + have h_pow_simp : + (kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹) = + -1 / (kB * (T.val : ℝ)^2) := by + calc + (kB)⁻¹ * (-((T.val : ℝ) ^ 2)⁻¹) + = -((kB)⁻¹ * ((T.val : ℝ) ^ 2)⁻¹) := by + ring + _ = -(1 / kB * (1 / (T.val : ℝ) ^ 2)) := by + simp [one_div] + _ = -1 / (kB * (T.val : ℝ) ^ 2) := by + rw [one_div] + field_simp [pow_two, mul_comm, + mul_left_comm, mul_assoc, + kB_ne_zero, h_T_ne_zero] + -- We derive `h_deriv_f` which states that `f` has + -- derivative `-1 / (kB * T.val²)` at `T.val`, by + -- combining `h_f_def`, `h_pow_simp`, and `h_deriv_aux`. + have h_deriv_f : + HasDerivAt f + (-1 / (kB * (T.val : ℝ)^2)) + (T.val : ℝ) := by + simpa [h_f_def, h_pow_simp] using h_deriv_aux + -- We derive `h_mem : (T.val : ℝ) ∈ Set.Ioi 0` from + -- `h_T_pos`, confirming that the evaluation point lies + -- in the domain. + have h_mem : (T.val : ℝ) ∈ Set.Ioi (0 : ℝ) := + h_T_pos + -- We conclude by converting `h_deriv_f` to a + -- `HasDerivWithinAt` and applying `congr` with `h_eq_on` + -- to replace `f` by `βFromReal` on the set. QED. + exact (h_deriv_f.hasDerivWithinAt).congr + h_eq_on (h_eq_on h_mem) + +/-- Lemma for `Temperature`: + +Chain rule for `β(T)`: if `F` has derivative `F'` at `β(T)` within +`(0, ∞)`, then the composition `t ↦ F(βFromReal(t))` has derivative +`F' * (-1 / (kB * T²))` within `(0, ∞)` at `T.val`. +-/ +lemma chain_rule_T_β {F : ℝ → ℝ} {F' : ℝ} + (T : Temperature) (h_T_pos : 0 < T.val) + (h_F_deriv : HasDerivWithinAt F F' (Set.Ioi 0) (T.β : ℝ)) : + HasDerivWithinAt (fun t : ℝ => F (βFromReal t)) + (F' * (-1 / (kB * (T.val : ℝ)^2))) + (Set.Ioi 0) (T.val : ℝ) := by + -- We derive `h_β_deriv` from `deriv_β_wrt_T`, which + -- gives the derivative of `βFromReal` at `T.val`. + have h_β_deriv := + deriv_β_wrt_T (T := T) h_T_pos + -- We derive `h_maps_to` which states that `βFromReal` + -- maps `(0, ∞)` into `(0, ∞)`, i.e. positive inputs + -- produce positive outputs. + have h_maps_to : + Set.MapsTo βFromReal (Set.Ioi 0) (Set.Ioi 0) := by + -- We introduce `t : ℝ` and the hypothesis + -- `h_t_pos : t ∈ Set.Ioi 0` (i.e. `0 < t`). + intro t h_t_pos + -- We derive `h_kB_mul_t_pos : 0 < kB * t` using + -- `mul_pos kB_pos h_t_pos`. + have h_kB_mul_t_pos : 0 < kB * t := + mul_pos kB_pos h_t_pos + -- We derive `h_quotient_pos : 0 < 1 / (kB * t)` using + -- `one_div_pos.mpr h_kB_mul_t_pos`. + have h_quotient_pos : 0 < (1 : ℝ) / (kB * t) := + one_div_pos.mpr h_kB_mul_t_pos + -- We derive `h_βFromReal_eq` which states that + -- `βFromReal t = 1 / (kB * t)` on `(0, ∞)`. + have h_βFromReal_eq : + βFromReal t = (1 : ℝ) / (kB * t) := + β_fun_T_eq_on_Ioi h_t_pos + -- We conclude by rewriting `βFromReal t` with + -- `h_βFromReal_eq` and applying `h_quotient_pos`. QED. + simpa [h_βFromReal_eq] using h_quotient_pos + -- We derive `h_β_at_T` which states that + -- `βFromReal (T.val : ℝ) = (T.β : ℝ)`, i.e. the + -- explicit formula agrees with the definition of `β`. + have h_β_at_T : + βFromReal (T.val : ℝ) = (T.β : ℝ) := by + -- We derive `h_T_pos_real : 0 < (T.val : ℝ)` from + -- `h_T_pos`. + have h_T_pos_real : 0 < (T.val : ℝ) := h_T_pos + -- We derive `h_βFromReal_eq_at_T` from + -- `β_fun_T_eq_on_Ioi h_T_pos_real`. + have h_βFromReal_eq_at_T := + β_fun_T_eq_on_Ioi h_T_pos_real + -- We conclude by simplifying with the definitions of + -- `β` and `toReal`. QED. + simpa [Temperature.β, Temperature.toReal] + using h_βFromReal_eq_at_T + -- We derive `h_F_deriv_at_βFromReal` which rewrites + -- `h_F_deriv` to use `βFromReal (T.val)` instead of + -- `(T.β : ℝ)`, using `h_β_at_T`. + have h_F_deriv_at_βFromReal : + HasDerivWithinAt F F' + (Set.Ioi 0) (βFromReal (T.val : ℝ)) := by + simpa [h_β_at_T] using h_F_deriv + -- We derive `h_composition` by applying the chain rule + -- (`HasDerivWithinAt.comp`) to compose `F` with + -- `βFromReal`, using `h_F_deriv_at_βFromReal`, + -- `h_β_deriv`, and `h_maps_to`. + have h_composition := + h_F_deriv_at_βFromReal.comp + (T.val : ℝ) h_β_deriv h_maps_to + -- We conclude by simplifying `h_composition` with + -- `mul_comm` to match the target derivative expression. + -- QED. + simpa [mul_comm] using h_composition + +end Temperature diff --git a/PhysLean/Thermodynamics/Temperature/Convergence.lean b/PhysLean/Thermodynamics/Temperature/Convergence.lean new file mode 100644 index 000000000..08f91ef28 --- /dev/null +++ b/PhysLean/Thermodynamics/Temperature/Convergence.lean @@ -0,0 +1,347 @@ +/- +Copyright (c) 2026 Joseph Tooby-Smith. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Trong-Nghia Be, Matteo Cipollina, Tan-Phuoc-Hung Le, Joseph Tooby-Smith +-/ +import PhysLean.Thermodynamics.Temperature.Basic + +/-! +# Convergence of inverse temperature maps + +This file proves that as the inverse temperature `β` tends to infinity, +the temperature `ofβ β` tends to zero. + +## Main results + +* `Temperature.eventually_pos_ofβ`: `ofβ` eventually produces positive temperatures. +* `Temperature.tendsto_toReal_ofβ_atTop` : The real representation of `ofβ β` + tends to `0` as `β → ∞`. +* `Temperature.tendsto_ofβ_atTop` : `ofβ β` tends to `0` from above as `β → ∞`. +-/ + +open NNReal + +namespace Temperature +open Constants +open Filter Topology + +/-- Lemma for `Temperature`: + +The function `ofβ` produces strictly positive real-valued temperatures +for sufficiently large inverse temperature β. +-/ +lemma eventually_pos_ofβ : ∀ᶠ b : ℝ≥0 in atTop, ((Temperature.ofβ b : Temperature) : ℝ) > 0 := by + -- We start by proving that for sufficiently large `b : ℝ≥0`, + -- we have `1 ≤ b` using `Filter.eventually_ge_atTop 1`, + -- which states that eventually, all elements of the filter + -- at infinity are greater than or equal to `1`. + -- This gives us the hypothesis `h_eventually_b_ge_one`. + have h_eventually_b_ge_one : ∀ᶠ b : ℝ≥0 in atTop, (1 : ℝ≥0) ≤ b := Filter.eventually_ge_atTop 1 + -- We then refine the goal using `h_eventually_b_ge_one.mono`, + -- which allows us to prove the desired property for all `b` that satisfy `1 ≤ b`. + -- The new goal is now `⊢ ∀ (x : ℝ≥0), 1 ≤ x → (ofβ x).toReal > 0`. + refine h_eventually_b_ge_one.mono ?_ + -- We introduce `b : ℝ≥0` and the hypothesis `h_b_ge_one : 1 ≤ b` from the goal. + -- The goal is now `⊢ (ofβ b).toReal > 0`. + intro b h_b_ge_one + -- We derive `h_b_pos : 0 < (b : ℝ)` using `zero_lt_one.trans_le h_b_ge_one`, + -- which states that if `0 < 1` and `1 ≤ b`, then `0 < b`. + have h_b_pos : 0 < (b : ℝ) := by + exact zero_lt_one.trans_le h_b_ge_one + -- We derive `h_denominator_pos : 0 < kB * (b : ℝ)` using `mul_pos kB_pos h_b_pos`, + -- which states that if `kB` is positive (proven by `kB_pos`) + -- and `b` is positive (proven by `h_b_pos`), then their product is positive. + have h_denominator_pos : 0 < kB * (b : ℝ) := by + exact mul_pos kB_pos h_b_pos + -- We derive `h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ))` + -- using `one_div_pos.mpr h_denominator_pos`, which states that if the denominator is positive, + -- then the reciprocal is also positive. + have h_quotient_pos : 0 < (1 : ℝ) / (kB * (b : ℝ)) := one_div_pos.mpr h_denominator_pos + -- We change the goal of `⊢ (ofβ b).toReal > 0` to its equivalent form + -- `⊢ (fun b => 1 / (kB * ↑b)) b > 0`. + change + (λ (b : ℝ≥0) => (1 : ℝ) / (kB * b)) b > 0 + -- We can apply `h_quotient_pos` to conclude that the goal is true, since `h_quotient_pos` states + -- that the expression `1 / (kB * (b : ℝ))` is positive, which is exactly what we need to show. + -- QED. + exact h_quotient_pos + +/-- Helper lemma for `Temperature`: + +Positivity of the epsilon-delta bound construction. +-/ +private lemma tendsto_const_inv_mul_bound_pos (a ε : ℝ) (h_a_pos : 0 < a) (h_ε_pos : 0 < ε) : + 0 < (1 / (a * ε)) + 1 := by + -- We derive `h_reciprocal_pos : 0 < (1 / (a * ε))` to show that the first term in the sum + -- is positive, which will allow us to conclude that the entire sum is positive. + have h_reciprocal_pos : 0 < (1 / (a * ε)) := by + -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, + -- which states that the product of two positive numbers is positive + -- (proof of `a` and `ε` being positive are given by `h_a_pos` and `h_ε_pos`). + have h_product_pos : 0 < a * ε := by + exact mul_pos h_a_pos h_ε_pos + -- We then apply `one_div_pos.mpr h_product_pos` to conclude that `1 / (a * ε)` is positive, + -- since `h_product_pos` states that the denominator is positive. QED for this part. + exact one_div_pos.mpr h_product_pos + -- Finally, we apply `add_pos` to `h_reciprocal_pos` and `zero_lt_one` to conclude that the sum + -- `(1 / (a * ε)) + 1` is positive, since both terms are positive. QED. + exact add_pos h_reciprocal_pos zero_lt_one + +/-- Helper lemma for `Temperature`: + +Product positivity via transitivity of ordering. +-/ +private lemma tendsto_const_inv_mul_product_pos_of_le (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) + (h_b_lower_bound_pos : 0 < b_lower_bound) (h_b_lower_bound_le_b : b_lower_bound ≤ b) : + 0 < a * b := by + -- We derive `h_b_pos : 0 < b` using `lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b`, + -- which states that if `b_lower_bound` is positive and `b_lower_bound ≤ b`, + -- then `b` is also positive. + have h_b_pos : 0 < b := lt_of_lt_of_le h_b_lower_bound_pos h_b_lower_bound_le_b + -- We then apply `mul_pos` to `h_a_pos` and `h_b_pos` to conclude that the product + -- `a * b` is positive. QED. + exact mul_pos h_a_pos h_b_pos + +/-- Helper lemma for `Temperature`: + +Antitonicity of reciprocal function with constant multiplier. +-/ +private lemma tendsto_const_inv_mul_reciprocal_antitone (a b_lower_bound b : ℝ) (h_a_pos : 0 < a) + (h_product_b_lower_bound_pos : 0 < a * b_lower_bound) + (h_b_lower_bound_le_b : b_lower_bound ≤ b) : + (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by + -- We derive `h_denom_le : (a * b_lower_bound) ≤ (a * b)` + -- using `mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos)`, which states that + -- if `b_lower_bound ≤ b` and `a` is non-negative, then multiplying both sides by `a` preserves + -- the inequality, giving us `a * b_lower_bound ≤ a * b`. + have h_denom_le : (a * b_lower_bound) ≤ (a * b) := by + exact mul_le_mul_of_nonneg_left h_b_lower_bound_le_b (le_of_lt h_a_pos) + -- Then we apply `one_div_le_one_div_of_le` to `h_product_b_lower_bound_pos` and `h_denom_le` + -- to conclude that the reciprocal of the larger denominator is less than or equal to the + -- reciprocal of the smaller denominator, which establishes the antitonicity. QED. + exact one_div_le_one_div_of_le h_product_b_lower_bound_pos h_denom_le + +/-- Helper lemma for `Temperature`: + +Evaluating the function at the constructed bound yields a value less than `ε`. +-/ +private lemma tendsto_const_inv_mul_at_bound_lt_epsilon (a ε : ℝ) (h_a_pos : 0 < a) + (h_ε_pos : 0 < ε) : + (1 : ℝ) / (a * ((1 / (a * ε)) + 1)) < ε := by + -- We first simplify the expression by performing field simplification with `field_simp` + -- to rewrite the goal into `⊢ 1 < 1 + a * ε`. + field_simp + -- We then simplify further using `simp` to reduce the goal to `⊢ 0 < a * ε`. + simp + -- We derive `h_product_pos : 0 < a * ε` using `mul_pos h_a_pos h_ε_pos`, + -- which states that the product of two positive numbers is positive. + have h_product_pos : 0 < a * ε := by + exact mul_pos h_a_pos h_ε_pos + -- Finally, we conclude that `⊢ 0 < a * ε` is true by `h_product_pos`. QED. + exact h_product_pos + + +/-- Helper lemma for `Temperature`: + +Conversion from nonnegative inequality to metric space distance. +-/ +private lemma tendsto_const_inv_mul_nonneg_to_dist (x ε : ℝ) (h_x_nonneg : 0 ≤ x) + (h_x_lt_ε : x < ε) : + dist x 0 < ε := by + -- We rewrite the goal `⊢ dist x 0 < ε` using `Real.dist_eq` to express the distance + -- in terms of absolute value (`dist x 0` is equal to `|x - 0|`), + -- and use `sub_zero` to simplify this to `⊢ |x| < ε`. + rw [Real.dist_eq, sub_zero] + -- We derive `h_abs_lt : |x| < ε`, by rewriting `|x|` as `x` using `abs_of_nonneg h_x_nonneg`, + -- which states that if `x` is nonnegative, then `|x|` is equal to `x`. + -- Then we apply `h_x_lt_ε` to conclude that `|x| < ε` is true. + have h_abs_lt : |x| < ε := by + rw [abs_of_nonneg h_x_nonneg] + exact h_x_lt_ε + -- Finally, we conclude that `⊢ |x| < ε` is true by `h_abs_lt`. QED. + exact h_abs_lt + +/-- Helper lemma for `Temperature`: + +Given a lower bound on `b` that ensures the function value is less than `ε`, +we can conclude that for any `b` greater than or equal to that lower bound, +the function value is nonnegative and less than `ε`. +-/ +private lemma tendsto_const_inv_mul_nonneg_and_lt_of_bound (a ε b_lower_bound b : ℝ) + (h_a_pos : 0 < a)(h_b_lower_bound_pos : 0 < b_lower_bound) + (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : + 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := by + -- We derive `h_prod_lower_bound_pos : 0 < a * b_lower_bound` + -- using `mul_pos h_a_pos h_b_lower_bound_pos`, which states that the product of + -- two positive numbers is positive (proof of `a` and `b_lower_bound` being positive are given by + -- `h_a_pos` and `h_b_lower_bound_pos`). + have h_prod_lower_pos : 0 < a * b_lower_bound := by + exact mul_pos h_a_pos h_b_lower_bound_pos + -- We then derive `h_prod_pos : 0 < a * b` using the previous lemma + -- `tendsto_const_inv_mul_product_pos_of_le`, which states that if `b` is greater than or equal + -- to a positive lower bound, then the product `a * b` is also positive. + have h_prod_pos : 0 < a * b := by + exact tendsto_const_inv_mul_product_pos_of_le a b_lower_bound b + h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b + -- We then derive `h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound)` + -- using the previous lemma `tendsto_const_inv_mul_reciprocal_antitone`, + -- which states that the reciprocal function is antitone. + have h_rec_le : (1 : ℝ) / (a * b) ≤ (1 : ℝ) / (a * b_lower_bound) := by + exact tendsto_const_inv_mul_reciprocal_antitone a b_lower_bound b + h_a_pos h_prod_lower_pos h_b_lower_bound_le_b + -- We then derive `h_lt : (1 : ℝ) / (a * b) < ε` using `lt_of_le_of_lt h_rec_le h_at_bound_lt`, + -- which states that if `1 / (a * b)` is less than or equal to `1 / (a * b_lower_bound)` + -- and `1 / (a * b_lower_bound)` is less than `ε`, then `1 / (a * b)` is also less than `ε`. + have h_lt : (1 : ℝ) / (a * b) < ε := by + exact lt_of_le_of_lt h_rec_le h_at_bound_lt + -- We then derive `h_nonneg : 0 ≤ (1 : ℝ) / (a * b)` + -- using `div_nonneg zero_le_one (le_of_lt h_prod_pos)`, + -- which states that the reciprocal of a positive number is nonnegative. + have h_nonneg : 0 ≤ (1 : ℝ) / (a * b) := by + exact div_nonneg zero_le_one (le_of_lt h_prod_pos) + -- Finally, we conclude that both `0 ≤ (1 : ℝ) / (a * b)` and `(1 : ℝ) / (a * b) < ε` hold by + -- the proofs of `h_nonneg` and `h_lt`. QED. + exact ⟨h_nonneg, h_lt⟩ + +/-- Helper lemma for `Temperature`: + +Given a lower bound on `b` that ensures the function value is less than `ε`, +we can conclude that for any `b` greater than or equal to that lower bound, +the distance from the function value to `0` is less than `ε`. +-/ +private lemma tendsto_const_inv_mul_dist_lt_of_bound (a ε b_lower_bound b : ℝ) + (h_a_pos : 0 < a) (h_b_lower_bound_pos : 0 < b_lower_bound) + (h_b_lower_bound_le_b : b_lower_bound ≤ b) (h_at_bound_lt : (1 : ℝ) / (a * b_lower_bound) < ε) : + dist ((1 : ℝ) / (a * b)) (0 : ℝ) < ε := by + -- We derive `h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε` + -- using the previous lemma `tendsto_const_inv_mul_nonneg_and_lt_of_bound`, + -- which states that for any `b` greater than or equal to the lower bound, + -- the function value is nonnegative and less than `ε`. + have h_nonneg_and_lt : 0 ≤ (1 : ℝ) / (a * b) ∧ (1 : ℝ) / (a * b) < ε := + tendsto_const_inv_mul_nonneg_and_lt_of_bound a ε b_lower_bound b + h_a_pos h_b_lower_bound_pos h_b_lower_bound_le_b h_at_bound_lt + -- Finally, we apply the previous lemma `tendsto_const_inv_mul_nonneg_to_dist` to conclude that + -- the distance from the function value to `0` is less than `ε`, since we have established that + -- the function value is nonnegative and less than `ε`. QED. + exact tendsto_const_inv_mul_nonneg_to_dist ((1 : ℝ) / (a * b)) ε + h_nonneg_and_lt.left h_nonneg_and_lt.right + +/-- Helper lemma for `Temperature`: + +As `b` tends to infinity, the distance from the function value `1 / (a * b)` to `0` +becomes less than any positive `ε` for sufficiently large `b`. + +(TODO) +-/ +private lemma tendsto_const_inv_mul_atTop_eventually_dist_lt (a : ℝ) (h_a_pos : 0 < a) (ε : ℝ) + (h_ε_pos : 0 < ε) : ∀ᶠ b : + ℝ≥0 in atTop, dist ((1 : ℝ) / (a * (b : ℝ))) (0 : ℝ) < ε := by + -- We construct a real number `B_real` defined as `(1 / (a * ε)) + 1`, + -- which serves as a candidate lower bound for `b` to ensure that the function value + -- is less than `ε`. + let B_real : ℝ := (1 / (a * ε)) + 1 + -- We then derive `h_B_real_pos : 0 < B_real` using the previous lemma + -- `tendsto_const_inv_mul_bound_pos`, which states that the constructed bound is positive. + have h_B_real_pos : 0 < B_real := by + exact tendsto_const_inv_mul_bound_pos a ε h_a_pos h_ε_pos + -- We then define a nonnegative real number `B_nnreal` by taking the nonnegative part of + -- `B_real`, ensuring that it is still positive. + let B_nnreal : ℝ≥0 := ⟨B_real, le_of_lt h_B_real_pos⟩ + -- We then derive `h_B_nnreal_pos : 0 < (B_nnreal : ℝ)` from `h_B_real_pos` + -- by noting that the coercion of `B_nnreal` to `ℝ` is exactly `B_real`, which is positive. QED. + have h_B_nnreal_pos : 0 < B_nnreal:= by + exact h_B_real_pos + -- We then refine the goal using `Filter.eventually_ge_atTop B_nnreal`, + -- which states that eventually, all elements of the filter at infinity are greater than or equal + -- to `B_nnreal`. The goal is now `⊢ ∀ (x : ℝ≥0), B_nnreal ≤ x → dist (1 / (a * ↑x)) 0 < ε`. + refine (Filter.eventually_ge_atTop B_nnreal).mono ?_ + -- We introduce `b : ℝ≥0` and the hypothesis `h_B_nnreal_le_b : B_nnreal ≤ b` from the goal. + --The goal is now `⊢ dist (1 / (a * ↑b)) 0 < ε`. + intro b h_B_nnreal_le_b + -- We derive `h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε` using the previous lemma + -- `tendsto_const_inv_mul_at_bound_lt_epsilon`, which states that evaluating the function + -- at the constructed bound yields a value less than `ε`. + have h_atB_lt : (1 : ℝ) / (a * (B_nnreal : ℝ)) < ε := by + exact tendsto_const_inv_mul_at_bound_lt_epsilon a ε h_a_pos h_ε_pos + -- Finally, we apply `tendsto_const_inv_mul_dist_lt_of_bound` + -- to conclude that the distance from the function value to `0` is less than `ε` + -- for any `b` greater than or equal to the constructed bound. QED. + exact tendsto_const_inv_mul_dist_lt_of_bound a ε (B_nnreal : ℝ) (b : ℝ) + h_a_pos h_B_nnreal_pos h_B_nnreal_le_b h_atB_lt + +/-- Helper lemma for `Temperature`: + +As `b` tends to infinity, the function value `1 / (a * b)` tends to `0` +in the sense of the metric space distance. +-/ +private lemma tendsto_const_inv_mul_atTop (a : ℝ) (h_a_pos : 0 < a) : + Tendsto (fun b : ℝ≥0 => (1 : ℝ) / (a * (b : ℝ))) atTop (𝓝 (0 : ℝ)) := by + -- We refine the goal using `Metric.tendsto_nhds.mpr`, + -- which allows us to prove the convergence by showing that for every positive `ε`, + -- the function values are eventually within `ε` of `0`. + -- The new goal is now `⊢ ∀ ε > 0, ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. + refine Metric.tendsto_nhds.mpr ?_ + -- We introduce `ε : ℝ` and the hypothesis `h_ε_pos : 0 < ε` from the goal. + -- The goal is now `⊢ ∀ᶠ (x : ℝ≥0) in atTop, dist (1 / (a * ↑x)) 0 < ε`. + intro ε h_ε_pos + -- We apply the previous lemma `tendsto_const_inv_mul_atTop_eventually_dist_lt` + -- to conclude that for sufficiently large `b`, the distance from the function value to `0` + -- is less than `ε`. QED. + exact tendsto_const_inv_mul_atTop_eventually_dist_lt a h_a_pos ε h_ε_pos + +/-- Lemma for `Temperature`: + +As the inverse temperature `β` tends to infinity, +the real-valued representation of the temperature `ofβ β` tends to `0` +in the sense of the metric space distance. +-/ +lemma tendsto_toReal_ofβ_atTop : + Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) atTop (𝓝 (0 : ℝ)) := by + -- We apply the previous lemma `tendsto_const_inv_mul_atTop` + -- with `a` set to `kB` and `h_a_pos` set to `kB_pos`, + -- which states that as `b` tends to infinity, the function value `1 / (kB * b)` tends to `0`. + -- Since `ofβ b` is defined as `1 / (kB * b)`, this directly implies the desired convergence. QED. + exact tendsto_const_inv_mul_atTop kB kB_pos + +/-- Lemma for `Temperature`: + +As the inverse temperature `β` tends to infinity, +the real-valued representation of the temperature `ofβ β` +tends to `0` from above (within the interval `(0, ∞)`). +-/ +lemma tendsto_ofβ_atTop : + Tendsto (fun b : ℝ≥0 => (Temperature.ofβ b : ℝ)) + atTop (nhdsWithin 0 (Set.Ioi 0)) := by + -- We derive `h_tendsto_nhds_zero` from + -- `tendsto_toReal_ofβ_atTop`, which states that as `β` + -- tends to infinity, the real-valued temperature + -- tends to `0` in the nhds sense. + have h_tendsto_nhds_zero := tendsto_toReal_ofβ_atTop + -- We derive `h_tendsto_principal_Ioi` which states that + -- as `β` tends to infinity, the real-valued temperature + -- eventually lies in the interval `(0, ∞)`, using + -- `tendsto_principal.mpr` and `eventually_pos_ofβ`. + have h_tendsto_principal_Ioi : + Tendsto (fun b : ℝ≥0 => + (Temperature.ofβ b : ℝ)) + atTop (𝓟 (Set.Ioi (0 : ℝ))) := + tendsto_principal.mpr + (by simpa using Temperature.eventually_pos_ofβ) + -- We combine `h_tendsto_nhds_zero` and + -- `h_tendsto_principal_Ioi` using `tendsto_inf.mpr` to + -- conclude that the function tends to `0` within the + -- infimum filter `nhds 0 ⊓ 𝓟 (Set.Ioi 0)`. + have h_tendsto_inf : + Tendsto (fun b : ℝ≥0 => + (Temperature.ofβ b : ℝ)) + atTop + ((nhds (0 : ℝ)) ⊓ 𝓟 (Set.Ioi (0 : ℝ))) := + tendsto_inf.mpr + ⟨h_tendsto_nhds_zero, h_tendsto_principal_Ioi⟩ + -- Since `nhdsWithin 0 (Set.Ioi 0)` is defined as + -- `nhds 0 ⊓ 𝓟 (Set.Ioi 0)`, the conclusion follows + -- directly from `h_tendsto_inf` by simplification. + -- QED. + simpa [nhdsWithin] using h_tendsto_inf + +end Temperature diff --git a/PhysLean/Thermodynamics/Temperature/Regularity.lean b/PhysLean/Thermodynamics/Temperature/Regularity.lean new file mode 100644 index 000000000..9d4572acd --- /dev/null +++ b/PhysLean/Thermodynamics/Temperature/Regularity.lean @@ -0,0 +1,261 @@ +/- +Copyright (c) 2026 Joseph Tooby-Smith. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Trong-Nghia Be, Matteo Cipollina, Tan-Phuoc-Hung Le, Joseph Tooby-Smith +-/ +import Mathlib.Analysis.Calculus.Deriv.Inv +import PhysLean.Thermodynamics.Temperature.Basic +import PhysLean.Meta.TODO.Basic + +/-! +# Regularity of the inverse temperature map + +This file proves continuity and differentiability properties of +`Temperature.ofβ : ℝ≥0 → Temperature` on the open interval `(0, ∞)`. + +## Main results + +* `Temperature.ofβ_continuousOn` : `ofβ` is continuous on `(0, ∞)`. +* `Temperature.ofβ_differentiableOn` : `ofβ` is differentiable on `(0, ∞)`. +-/ + +open NNReal + +namespace Temperature +open Constants +open Filter Topology + +/-! ### Regularity of `ofβ` === TODO TIL THE END OF THE FILE -/ + +/-- Helper lemma for `Temperature`: + +The denominator of `ofβ` is nonnegative. +-/ +private lemma ofβ_den_nonneg (b : ℝ≥0) : 0 ≤ kB * (b : ℝ) := by + -- We apply `mul_nonneg` to show that the product `kB * (b : ℝ)` is nonnegative by showing that + -- both factors are nonnegative. + apply mul_nonneg + -- `case ha`: The goal is `⊢ 0 ≤ kB`, which is true by the lemma `kB_nonneg`, since the Boltzmann + -- constant is a positive physical constant. QED for this case. + · exact kB_nonneg + -- `case hb`: The goal is `⊢ 0 ≤ (b : ℝ)`, which is true by the fact that `b` of type `ℝ≥0` + -- carries the proof `b.property : 0 ≤ (b : ℝ)`. QED for this case. + · exact b.property + -- All cases have been proven. QED. + +/-- Helper lemma for `Temperature`: + +The real-valued expression `1 / (kB * b)` is nonnegative. +-/ +private lemma ofβ_real_nonneg (b : ℝ≥0) : 0 ≤ (1 : ℝ) / (kB * (b : ℝ)) := by + -- We apply `div_nonneg` to show that the fraction `1 / (kB * b)` is nonnegative by showing that + -- both the numerator and the denominator are nonnegative. + apply div_nonneg + -- `case ha`: The goal is `⊢ 0 ≤ 1`, which is true by the lemma `zero_le_one`. QED for this case. + · exact zero_le_one + -- `case hb`: The goal is `⊢ 0 ≤ kB * (b : ℝ)`, which is true by the lemma `ofβ_den_nonneg b`. + -- QED for this case. + · exact ofβ_den_nonneg b + -- All cases have been proven. QED. + +/-- Helper lemma for `Temperature`: + +Continuity at a positive point for the real formula `(t : ℝ) ↦ (1 : ℝ) / (kB * t)`. +-/ +private lemma ofβ_realExpr_continuousAt_real (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ) := by + -- We refine the goal using `ContinuousAt.div₀`, which requires us to prove continuity of the + -- numerator and denominator separately: + refine ContinuousAt.div₀ ?_ ?_ ?_ + -- `case refine_1`: The goal is `⊢ ContinuousAt (fun t => 1) ↑x`. + -- This is true because constant functions are continuous everywhere. We use `fun_prop` to + -- establish this. + · fun_prop + -- `case refine_2`: The goal is `⊢ ContinuousAt (HMul.hMul kB) ↑x`. + -- This is true because multiplication by a constant is continuous everywhere. + -- We use `fun_prop` to establish this. + · fun_prop + -- `case refine_3`: The goal is `⊢ kB * ↑x ≠ 0`. + -- We have the hypothesis `h_x_ne_zero : (x : ℝ) ≠ 0` derived from `ne_of_gt h_x_pos`; + -- which means: "Given a and b, if a > b, then a ≠ b" - and since we have `0 < x`, + -- we conclude `x ≠ 0`. + · have h_x_ne_zero : (x : ℝ) ≠ 0 := by + exact (ne_of_gt h_x_pos) + exact mul_ne_zero kB_ne_zero h_x_ne_zero + +/-- Helper lemma for `Temperature`: + +Continuity at a positive point for the same formula on `ℝ≥0`. +-/ +private lemma ofβ_realExpr_continuousAt_nnreal (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (fun (b : ℝ≥0) => (1 : ℝ) / (kB * b)) x := by + -- We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`. + -- This is the same as the function in the goal, but we give it a name for clarity. + let f : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (1 : ℝ) / (kB * b) + -- We define `g : ℝ → ℝ` as `g (t : ℝ) := (1 : ℝ) / (kB * t)`. + -- This is the same formula as `f`, but defined on `ℝ`. + let g : ℝ → ℝ := fun (t : ℝ) => (1 : ℝ) / (kB * t) + -- We define `h : ℝ≥0 → ℝ` as `h (b : ℝ≥0) := (b : ℝ)`. + -- This is the coercion from `ℝ≥0` to `ℝ`. + let h : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (b : ℝ) + -- We then prove that `f = g ∘ h` by simplifying both sides and showing they are equal. + -- This is done by `rfl`, since both sides are definitionally equal. + have f_eq_g_comp_h : f = (g ∘ h) := by + rfl + -- We then prove that `g` is continuous at `x : ℝ` using the previous lemma + -- `ofβ_realExpr_continuousAt_real x h_x_pos`, resulting in the hypothesis `h_continuousAt_real`. + have h_continuousAt_real : ContinuousAt g (x : ℝ) := ofβ_realExpr_continuousAt_real x h_x_pos + -- We also prove that `h` is continuous at `x : ℝ≥0` using `continuous_subtype_val.continuousAt`, + -- which states that the coercion from a subtype to its parent type is continuous at every point, + -- resulting in the hypothesis `h_continuousAt_subtype`. + have h_continuousAt_subtype : ContinuousAt h (x : ℝ≥0) := continuous_subtype_val.continuousAt + -- Finally, we conclude that `f` is continuous at `x` by using the composition of + -- continuous functions: `h_continuousAt_real.comp h_continuousAt_subtype`. QED. + exact h_continuousAt_real.comp h_continuousAt_subtype + +/-- Helper lemma for `Temperature`: + +Continuity at a positive point for the `ℝ≥0`-valued `val` component of `ofβ`. +-/ +private lemma ofβ_val_continuousAt (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (fun (b : ℝ≥0) => ((ofβ b).val : ℝ≥0)) x := by + -- We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`, + -- which is the real-valued formula used by `ofβ`. + let f : ℝ≥0 → ℝ := fun b => (1 : ℝ) / (kB * b) + -- Then, we prove that `f` is continuous at `x` using the previous lemma + -- `ofβ_realExpr_continuousAt_nnreal x h_x_pos`, + -- resulting in the hypothesis `h_f_continuousAt`. + have h_continuousAt_nnreal : ContinuousAt f x := by + exact ofβ_realExpr_continuousAt_nnreal x h_x_pos + -- Next, we prove that `f` is nonnegative for all `b : ℝ≥0` using the lemma `ofβ_real_nonneg b`, + -- resulting in the hypothesis `h_f_nonneg`. + have h_f_nonneg : ∀ b : ℝ≥0, 0 ≤ f (b : ℝ≥0) := by + intro b + exact ofβ_real_nonneg b + -- We then define `g : ℝ≥0 → ℝ≥0` as `g (b : ℝ≥0) := ⟨f b, h_f_nonneg b⟩`, + -- which is the same formula as `f` but with codomain restricted to `ℝ≥0`. + let g : ℝ≥0 → ℝ≥0 := fun b => (⟨f b, h_f_nonneg b⟩ : ℝ≥0) + -- We prove that `g` is continuous at `x` by using the fact that if a real-valued function + -- is continuous, then its codomain-restricted version is also continuous. + -- This gives us the hypothesis `h_g_continuousAt`. + have h_g_continuousAt : ContinuousAt g x := by + exact h_continuousAt_nnreal.codRestrict h_f_nonneg + -- Finally, we conclude that the `val` component of `ofβ` is continuous at `x` + -- by using the hypothesis `h_g_continuousAt`, + -- since `g` is definitionally equal to the function we want to prove continuous. QED. + exact h_g_continuousAt + +/-- Helper lemma for `Temperature`: + +The topology on `Temperature` is induced by the coercion to `ℝ≥0`. +-/ +private lemma temperature_val_isInducing : + Topology.IsInducing (fun T : Temperature => (T.val : ℝ≥0)) := by + -- This is immediate from the topology instance definition, + -- which is exactly `induced` by this coercion map. + -- Therefore the witness is `⟨rfl⟩`. + exact ⟨rfl⟩ + +/-- Helper lemma for `Temperature`: + +Continuity of `ofβ` at every strictly positive input. +-/ +private lemma ofβ_continuousAt_of_pos (x : ℝ≥0) (h_x_pos : 0 < x) : + ContinuousAt (ofβ : ℝ≥0 → Temperature) x := by + -- We refine the goal using `temperature_val_isInducing.continuousAt_iff`, + -- which states that continuity of a function into `Temperature` can be checked + -- by continuity of its composition with the coercion to `ℝ≥0`. + -- The goal is now `⊢ ContinuousAt ((fun T => T.val) ∘ ofβ) x`. + refine (temperature_val_isInducing.continuousAt_iff).mpr ?_ + -- This is exactly the content of the previous lemma `ofβ_val_continuousAt x h_x_pos`, + -- so we apply that to conclude. QED. + exact ofβ_val_continuousAt x h_x_pos + +/-- Lemma for `Temperature`: + +The function `ofβ` is continuous on the interval `(0, ∞)`. +-/ +lemma ofβ_continuousOn : ContinuousOn (ofβ : ℝ≥0 → Temperature) (Set.Ioi 0) := by + -- We refine the goal using `continuousOn_of_forall_continuousAt`, + -- which reduces continuity on a set to continuity at every point in that set. + -- The goal is now `⊢ ∀ x ∈ Set.Ioi 0, ContinuousAt ofβ x`. + refine continuousOn_of_forall_continuousAt ?_ + -- We introduce `x : ℝ≥0` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. + intro x h_x_in_set + -- From `h_x_in_set`, we derive `h_x_pos : 0 < x` by: + have h_x_pos : 0 < x := by + -- Simplifying the definition of `Set.Ioi 0`, which states that `x ∈ Set.Ioi 0` means `0 < x`. + simp at h_x_in_set + -- Extracting the strict inequality `0 < x` from this definition. + exact h_x_in_set + -- Given `x : ℝ≥0` and `h_x_pos : 0 < x`, + -- we can prove the goal with `ofβ_continuousAt_of_pos x h_x_pos`. QED. + exact ofβ_continuousAt_of_pos x h_x_pos + +/-- Lemma for `Temperature`: + +The function `ofβ` is differentiable on the interval `(0, ∞)`. +-/ +lemma ofβ_differentiableOn : + DifferentiableOn ℝ (fun (x : ℝ) => ((ofβ (Real.toNNReal x)).val : ℝ)) (Set.Ioi 0) := by + -- We refine the goal using `DifferentiableOn.congr`, which allows us to prove differentiability + -- by showing that the function is equal to a simpler function that we can easily differentiate. + -- We now have two cases: + refine DifferentiableOn.congr (f := fun (x : ℝ) => (1 : ℝ) / (kB * x)) ?_ ?_ + -- `case refine_1` : The goal is `⊢ DifferentiableOn ℝ (fun x => 1 / (kB * x)) (Set.Ioi 0)`. + -- We further refine this using `DifferentiableOn.fun_div`, which requires us + -- to prove differentiability of the numerator and denominator separately, + -- and that the denominator is nonzero on the set: + · refine DifferentiableOn.fun_div ?_ ?_ ?_ + -- `case refine_1.refine_1` : The goal is `⊢ DifferentiableOn ℝ (fun x => 1) (Set.Ioi 0)`. + -- This is true because constant functions are differentiable everywhere. + -- We use `fun_prop` to establish this. + · fun_prop + -- `case refine_1.refine_2` : The goal is `⊢ DifferentiableOn ℝ (HMul.hMul kB) (Set.Ioi 0)`. + -- This is true because multiplication by a constant is differentiable everywhere. + -- We use `fun_prop` to establish this. + · fun_prop + -- `case refine_1.refine_3` : The goal is `⊢ ∀ x ∈ Set.Ioi 0, kB * x ≠ 0`. + -- We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. + -- The goal is now `⊢ kB * x ≠ 0`. + · intro x h_x_in_set + -- We derive `h_x_ne_zero : x ≠ 0` from `h_x_in_set` by noting that + -- if `x` is strictly greater than `0`, then it cannot be equal to `0`. + have h_x_ne_zero : x ≠ 0 := by + exact ne_of_gt h_x_in_set + -- We then apply `mul_ne_zero` to conclude that `kB * x` is nonzero. + apply mul_ne_zero + -- The first factor `kB` is nonzero by `kB_ne_zero`. + · exact kB_ne_zero + -- The second factor `x` is nonzero by `h_x_ne_zero`. + -- This completes the proof of this case. QED for `refine_1.refine_3`. + -- QED for `refine_1`. + · exact h_x_ne_zero + -- `case refine_2` : The goal is + -- `⊢ ∀ x ∈ Set.Ioi 0, ↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. + -- We introduce `x : ℝ` and the hypothesis `h_x_in_set : x ∈ Set.Ioi 0` from the goal. + -- The goal is now `↑(ofβ x.toNNReal).val = (fun x => 1 / (kB * x)) x`. + · intro x h_x_in_set + -- We derive `h_x_pos : 0 < x` from `h_x_in_set` by simplifying the definition of `Set.Ioi 0` + -- to extract the strict inequality `0 < x`. + have h_x_pos : 0 < x := by + simp at h_x_in_set + exact h_x_in_set + -- We also derive `h_x_nonneg : 0 ≤ x` from `h_x_pos` by noting that + -- if `x` is strictly greater than `0`, then it can be considered as + -- "greater than or equal to `0`" as well (since `0 < x` implies `0 ≤ x`). + have h_x_nonneg : 0 ≤ x := by + simpa using h_x_pos.le + -- We then simplify the goal using `simp` to get a new goal + -- that is a disjunction: `⊢ 0 ≤ x ∨ kB = 0`. + simp + -- We only have to prove the left disjunct `0 ≤ x` since `kB` is nonzero by `kB_ne_zero` + -- (thus the right disjunct is false). + left + -- We have already established `h_x_nonneg : 0 ≤ x`, so we can conclude this case + -- by left disjunction and using `h_x_nonneg`. + -- This completes the proof of this case. QED for `refine_2`. + -- All cases have been proven. QED. + simp [h_x_nonneg] + +end Temperature From 567c1d97e3c13097dd35e002eb69abee492c7baa Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 07:49:18 +0000 Subject: [PATCH 08/12] =?UTF-8?q?style(thermodynamics):=20fix=20formatting?= =?UTF-8?q?=20in=20=CE=B2FromReal=20docstring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PhysLean/Thermodynamics/Temperature/Calculus.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PhysLean/Thermodynamics/Temperature/Calculus.lean b/PhysLean/Thermodynamics/Temperature/Calculus.lean index 9a9d84988..37aa346c9 100644 --- a/PhysLean/Thermodynamics/Temperature/Calculus.lean +++ b/PhysLean/Thermodynamics/Temperature/Calculus.lean @@ -33,7 +33,7 @@ open scoped ENNReal Map a real number `t` to the inverse temperature `β` corresponding to the temperature `Real.toNNReal t` (`max t 0`), returned as a real number. -Note: +- Note: 1. Why `ℝ` instead of `ℝ≥0`, if `β` is of type `ℝ≥0`? -/ From 11ce0c3980e3fe3364582c725ee4d2dfa8255fd8 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 08:59:52 +0000 Subject: [PATCH 09/12] feat(thermodynamics): enhance temperature scale functionality * Introduce `TemperatureScale` structure with detailed documentation. * Implement conversion functions between kelvin and affine scales. * Add lemmas to verify the identity of conversions. * Define specific temperature scales: Celsius, Fahrenheit, and Rankine. * Improve documentation for clarity and completeness. * Refactor existing functions for better readability and maintainability. --- .../Temperature/TemperatureScales.lean | 504 ++++++++++++++---- .../Temperature/TemperatureUnits.lean | 257 +++++++-- 2 files changed, 598 insertions(+), 163 deletions(-) diff --git a/PhysLean/Thermodynamics/Temperature/TemperatureScales.lean b/PhysLean/Thermodynamics/Temperature/TemperatureScales.lean index 87403a336..fefe15237 100644 --- a/PhysLean/Thermodynamics/Temperature/TemperatureScales.lean +++ b/PhysLean/Thermodynamics/Temperature/TemperatureScales.lean @@ -6,236 +6,516 @@ Authors: Trong-Nghia Be, Tan-Phuoc-Hung Le import PhysLean.Thermodynamics.Temperature.Basic import PhysLean.Thermodynamics.Temperature.TemperatureUnits /-! - # Affine temperature scales === TODO TIL THE END OF THE FILE -`Temperature` stores absolute temperature in kelvin (`ℝ≥0`), which is the physically meaningful quantity used by thermodynamics and statistical mechanics. - -This file introduces affine display scales (such as Celsius and Fahrenheit), where the reading is allowed to be negative while the corresponding absolute temperature remains nonnegative. +`Temperature` stores absolute temperature in kelvin (`ℝ≥0`), which +is the physically meaningful quantity used by thermodynamics and +statistical mechanics. +This file introduces affine display scales (such as Celsius and +Fahrenheit), where the reading is allowed to be negative while the +corresponding absolute temperature remains nonnegative. -/ open NNReal -/-- An affine scale for reading temperatures. - -- `unit` gives the size of one degree on this scale as a multiplicative temperature interval. -- `absoluteZero` is the reading on this scale corresponding to `0 K`. - For example, on the Celsius scale this is `-273.15`. +/-- The type `TemperatureScale` represents an affine temperature + scale, such as Celsius or Fahrenheit. + - `unit` of type `TemperatureUnit`: The size of one degree on + this scale as a multiplicative temperature interval. + - `absoluteZero` of type `ℝ`: The reading on this scale + corresponding to `0 K`. For example, on the Celsius scale this + is `-273.15`. -/ structure TemperatureScale where - /-- The multiplicative interval unit for one degree on this scale. -/ + /-- The multiplicative interval unit for one degree on this + scale. -/ unit : TemperatureUnit /-- The reading corresponding to absolute zero (`0 K`). -/ absoluteZero : ℝ namespace TemperatureScale -/-- Convert a reading in an affine temperature scale into kelvin as a real number. +/-- Function for `TemperatureScale`: + +Convert a reading in an affine temperature scale into kelvin as a +real number. +-/ +noncomputable def toKelvinReal + (s : TemperatureScale) (reading : ℝ) : ℝ := + (reading - s.absoluteZero) * + (s.unit / TemperatureUnit.kelvin : ℝ) -- Input: - - `s` of type `TemperatureScale`: the affine temperature scale. - - `reading` of type `ℝ`: the reading on the affine scale. -- Output: - - result of type `ℝ`: the corresponding temperature in kelvin as a real number. +/-- Function for `TemperatureScale`: -- Algorithm: - 1. Subtract `s.absoluteZero` from `reading` to get the temperature interval above absolute zero. - 2. Multiply the result by the ratio of `s.unit` to `TemperatureUnit.kelvin` to convert the interval to kelvin. +Convert a kelvin value into a reading in an affine temperature scale +as a real number. -/ -noncomputable def toKelvinReal (s : TemperatureScale) (reading : ℝ) : ℝ := - (reading - s.absoluteZero) * (s.unit / TemperatureUnit.kelvin : ℝ) +noncomputable def fromKelvinReal + (s : TemperatureScale) (k : ℝ) : ℝ := + s.absoluteZero + + k * (TemperatureUnit.kelvin / s.unit : ℝ) -/-- Convert a kelvin value into a reading in an affine temperature scale as a real number. -/ -noncomputable def fromKelvinReal (s : TemperatureScale) (k : ℝ) : ℝ := - s.absoluteZero + k * (TemperatureUnit.kelvin / s.unit : ℝ) +/-- Lemma for `TemperatureScale`: -lemma fromKelvinReal_toKelvinReal (s : TemperatureScale) (reading : ℝ) : - fromKelvinReal s (toKelvinReal s reading) = reading := by +Converting to kelvin and back to the affine scale is the identity. +-/ +lemma fromKelvinReal_toKelvinReal + (s : TemperatureScale) (reading : ℝ) : + fromKelvinReal s (toKelvinReal s reading) = + reading := by + -- We unfold the definitions of `fromKelvinReal` and + -- `toKelvinReal` to expose the underlying expressions. unfold fromKelvinReal toKelvinReal - have hmul : (s.unit / TemperatureUnit.kelvin : ℝ) * - (TemperatureUnit.kelvin / s.unit : ℝ) = 1 := by + -- We derive `hmul` which states that the product of the + -- unit ratio and its inverse equals `1`, using the chain + -- rule for division `div_mul_div_coe`. + have hmul : + (s.unit / TemperatureUnit.kelvin : ℝ) * + (TemperatureUnit.kelvin / s.unit : ℝ) = 1 := by calc - (s.unit / TemperatureUnit.kelvin : ℝ) * (TemperatureUnit.kelvin / s.unit : ℝ) + (s.unit / TemperatureUnit.kelvin : ℝ) * + (TemperatureUnit.kelvin / s.unit : ℝ) = (s.unit / s.unit : ℝ) := - TemperatureUnit.div_mul_div_coe s.unit TemperatureUnit.kelvin s.unit + TemperatureUnit.div_mul_div_coe + s.unit TemperatureUnit.kelvin s.unit _ = 1 := by simp + -- We conclude by algebraic simplification using `hmul` + -- to replace the product of ratios with `1`. QED. calc s.absoluteZero + - ((reading - s.absoluteZero) * (s.unit / TemperatureUnit.kelvin : ℝ)) * - (TemperatureUnit.kelvin / s.unit : ℝ) + ((reading - s.absoluteZero) * + (s.unit / TemperatureUnit.kelvin : ℝ)) * + (TemperatureUnit.kelvin / s.unit : ℝ) = s.absoluteZero + (reading - s.absoluteZero) * ((s.unit / TemperatureUnit.kelvin : ℝ) * - (TemperatureUnit.kelvin / s.unit : ℝ)) := by ring - _ = s.absoluteZero + (reading - s.absoluteZero) * 1 := by rw [hmul] + (TemperatureUnit.kelvin / s.unit : ℝ)) := + by ring + _ = s.absoluteZero + + (reading - s.absoluteZero) * 1 := by + rw [hmul] _ = reading := by ring -lemma toKelvinReal_fromKelvinReal (s : TemperatureScale) (k : ℝ) : +/-- Lemma for `TemperatureScale`: + +Converting from kelvin to the affine scale and back to kelvin is the +identity. +-/ +lemma toKelvinReal_fromKelvinReal + (s : TemperatureScale) (k : ℝ) : toKelvinReal s (fromKelvinReal s k) = k := by + -- We unfold the definitions of `fromKelvinReal` and + -- `toKelvinReal` to expose the underlying expressions. unfold fromKelvinReal toKelvinReal - have hmul : (TemperatureUnit.kelvin / s.unit : ℝ) * - (s.unit / TemperatureUnit.kelvin : ℝ) = 1 := by + -- We derive `hmul` which states that the product of the + -- unit ratio and its inverse equals `1`, using the chain + -- rule for division `div_mul_div_coe`. + have hmul : + (TemperatureUnit.kelvin / s.unit : ℝ) * + (s.unit / TemperatureUnit.kelvin : ℝ) = 1 := by calc - (TemperatureUnit.kelvin / s.unit : ℝ) * (s.unit / TemperatureUnit.kelvin : ℝ) - = (TemperatureUnit.kelvin / TemperatureUnit.kelvin : ℝ) := - TemperatureUnit.div_mul_div_coe TemperatureUnit.kelvin s.unit TemperatureUnit.kelvin + (TemperatureUnit.kelvin / s.unit : ℝ) * + (s.unit / TemperatureUnit.kelvin : ℝ) + = (TemperatureUnit.kelvin / + TemperatureUnit.kelvin : ℝ) := + TemperatureUnit.div_mul_div_coe + TemperatureUnit.kelvin s.unit + TemperatureUnit.kelvin _ = 1 := by simp + -- We conclude by algebraic simplification using `hmul` + -- to replace the product of ratios with `1`. QED. calc - (s.absoluteZero + k * (TemperatureUnit.kelvin / s.unit : ℝ) - s.absoluteZero) * + (s.absoluteZero + + k * (TemperatureUnit.kelvin / s.unit : ℝ) - + s.absoluteZero) * (s.unit / TemperatureUnit.kelvin : ℝ) - = (k * (TemperatureUnit.kelvin / s.unit : ℝ)) * - (s.unit / TemperatureUnit.kelvin : ℝ) := by ring - _ = k * ((TemperatureUnit.kelvin / s.unit : ℝ) * - (s.unit / TemperatureUnit.kelvin : ℝ)) := by ring + = (k * + (TemperatureUnit.kelvin / s.unit : ℝ)) * + (s.unit / TemperatureUnit.kelvin : ℝ) := + by ring + _ = k * + ((TemperatureUnit.kelvin / s.unit : ℝ) * + (s.unit / TemperatureUnit.kelvin : ℝ)) := + by ring _ = k * 1 := by rw [hmul] _ = k := by ring -/-- Kelvin scale. -/ -def kelvin : TemperatureScale := ⟨TemperatureUnit.kelvin, 0⟩ +/-- Function for `TemperatureScale`: + +The kelvin scale, with unit size equal to one kelvin and zero +offset. +-/ +def kelvin : TemperatureScale := + ⟨TemperatureUnit.kelvin, 0⟩ + +/-- Function for `TemperatureScale`: -/-- Celsius scale. -/ -noncomputable def celsius : TemperatureScale := ⟨TemperatureUnit.kelvin, -(27315 : ℝ) / 100⟩ +The Celsius scale, with unit size equal to one kelvin and absolute +zero at `-273.15`. +-/ +noncomputable def celsius : TemperatureScale := + ⟨TemperatureUnit.kelvin, -(27315 : ℝ) / 100⟩ + +/-- Function for `TemperatureScale`: -/-- Rankine scale. -/ -noncomputable def rankine : TemperatureScale := ⟨TemperatureUnit.rankine, 0⟩ +The Rankine scale, with unit size equal to one rankine degree and +zero offset. +-/ +noncomputable def rankine : TemperatureScale := + ⟨TemperatureUnit.rankine, 0⟩ -/-- Fahrenheit scale. -/ -noncomputable def fahrenheit : TemperatureScale := ⟨TemperatureUnit.rankine, -(45967 : ℝ) / 100⟩ +/-- Function for `TemperatureScale`: +The Fahrenheit scale, with unit size equal to one rankine degree and +absolute zero at `-459.67`. +-/ +noncomputable def fahrenheit : TemperatureScale := + ⟨TemperatureUnit.rankine, -(45967 : ℝ) / 100⟩ + +/-- Simplification lemma for `TemperatureScale`: + +Converting a kelvin reading to kelvin is the identity. +-/ @[simp] -lemma toKelvinReal_kelvin (k : ℝ) : toKelvinReal kelvin k = k := by +lemma toKelvinReal_kelvin (k : ℝ) : + toKelvinReal kelvin k = k := by + -- We simplify using the definitions of `toKelvinReal` + -- and `kelvin`. QED. simp [toKelvinReal, kelvin] +/-- Simplification lemma for `TemperatureScale`: + +Converting a kelvin value to a kelvin reading is the identity. +-/ @[simp] -lemma fromKelvinReal_kelvin (k : ℝ) : fromKelvinReal kelvin k = k := by +lemma fromKelvinReal_kelvin (k : ℝ) : + fromKelvinReal kelvin k = k := by + -- We simplify using the definitions of `fromKelvinReal` + -- and `kelvin`. QED. simp [fromKelvinReal, kelvin] +/-- Simplification lemma for `TemperatureScale`: + +Converting a Celsius reading `c` to kelvin yields +`c + 273.15`. +-/ @[simp] lemma toKelvinReal_celsius (c : ℝ) : - toKelvinReal celsius c = c + (27315 : ℝ) / 100 := by + toKelvinReal celsius c = + c + (27315 : ℝ) / 100 := by + -- We compute `toKelvinReal celsius c` step by step. calc toKelvinReal celsius c - = (c - (-(27315 : ℝ) / 100)) * (TemperatureUnit.kelvin / TemperatureUnit.kelvin : ℝ) := by - rfl + = (c - (-(27315 : ℝ) / 100)) * + (TemperatureUnit.kelvin / + TemperatureUnit.kelvin : ℝ) := by + rfl + -- We simplify `kelvin / kelvin` to `1` and the + -- subtraction of a negative to addition. _ = c - (-(27315 : ℝ) / 100) := by simp + -- We conclude by the algebraic identity + -- `c - (-273.15) = c + 273.15`. QED. _ = c + (27315 : ℝ) / 100 := by ring +/-- Simplification lemma for `TemperatureScale`: + +Converting a kelvin value to Celsius yields +`-273.15 + k`. +-/ @[simp] lemma fromKelvinReal_celsius (k : ℝ) : - fromKelvinReal celsius k = -(27315 : ℝ) / 100 + k := by + fromKelvinReal celsius k = + -(27315 : ℝ) / 100 + k := by + -- We simplify using the definitions of `fromKelvinReal`, + -- `celsius`, and commutativity of addition. QED. simp [fromKelvinReal, celsius, add_comm] +/-- Simplification lemma for `TemperatureScale`: + +Converting a Fahrenheit reading `f` to kelvin yields +`(f + 459.67) * (5 / 9)`. +-/ @[simp] lemma toKelvinReal_fahrenheit (f : ℝ) : - toKelvinReal fahrenheit f = (f + (45967 : ℝ) / 100) * (5 / 9 : ℝ) := by + toKelvinReal fahrenheit f = + (f + (45967 : ℝ) / 100) * (5 / 9 : ℝ) := by + -- We compute `toKelvinReal fahrenheit f` step by step. calc toKelvinReal fahrenheit f - = (f - (-(45967 : ℝ) / 100)) * (TemperatureUnit.rankine / TemperatureUnit.kelvin : ℝ) := by - rfl - _ = (f + (45967 : ℝ) / 100) * (5 / 9 : ℝ) := by - have hneg : f - (-(45967 : ℝ) / 100) = f + (45967 : ℝ) / 100 := by ring + = (f - (-(45967 : ℝ) / 100)) * + (TemperatureUnit.rankine / + TemperatureUnit.kelvin : ℝ) := by + rfl + -- We simplify the subtraction of a negative to + -- addition and evaluate `rankine / kelvin = 5/9`. + _ = (f + (45967 : ℝ) / 100) * + (5 / 9 : ℝ) := by + -- We derive that `f - (-459.67) = f + 459.67`. + have hneg : + f - (-(45967 : ℝ) / 100) = + f + (45967 : ℝ) / 100 := by ring + -- We rewrite using `hneg` and simplify the rankine + -- to kelvin ratio. QED. rw [hneg] - simp [TemperatureUnit.rankine, TemperatureUnit.scale_div_self] + simp [TemperatureUnit.rankine, + TemperatureUnit.scale_div_self] + +/-- Simplification lemma for `TemperatureScale`: +Converting a kelvin value to Fahrenheit yields +`-459.67 + k * (9 / 5)`. +-/ @[simp] lemma fromKelvinReal_fahrenheit (k : ℝ) : - fromKelvinReal fahrenheit k = -(45967 : ℝ) / 100 + k * (9 / 5 : ℝ) := by - simp [fromKelvinReal, fahrenheit, TemperatureUnit.rankine, TemperatureUnit.self_div_scale, - add_comm] - + fromKelvinReal fahrenheit k = + -(45967 : ℝ) / 100 + k * (9 / 5 : ℝ) := by + -- We simplify using the definitions of `fromKelvinReal`, + -- `fahrenheit`, `rankine`, `self_div_scale`, and + -- commutativity of addition. QED. + simp [fromKelvinReal, fahrenheit, + TemperatureUnit.rankine, + TemperatureUnit.self_div_scale, add_comm] + +/-- Lemma for `TemperatureScale`: + +The kelvin value of a Celsius reading is nonnegative if and only if +the reading is at or above `-273.15`. +-/ lemma zero_le_toKelvinReal_celsius_iff (c : ℝ) : - 0 ≤ toKelvinReal celsius c ↔ (-(27315 : ℝ) / 100) ≤ c := by + 0 ≤ toKelvinReal celsius c ↔ + (-(27315 : ℝ) / 100) ≤ c := by + -- We rewrite the goal using `toKelvinReal_celsius` to + -- get the explicit formula. rw [toKelvinReal_celsius] + -- We prove both directions using `linarith`. QED. constructor <;> intro h <;> linarith +/-- Lemma for `TemperatureScale`: + +The kelvin value of a Fahrenheit reading is nonnegative if and only +if the reading is at or above `-459.67`. +-/ lemma zero_le_toKelvinReal_fahrenheit_iff (f : ℝ) : - 0 ≤ toKelvinReal fahrenheit f ↔ (-(45967 : ℝ) / 100) ≤ f := by + 0 ≤ toKelvinReal fahrenheit f ↔ + (-(45967 : ℝ) / 100) ≤ f := by + -- We rewrite the goal using `toKelvinReal_fahrenheit` + -- to get the explicit formula. rw [toKelvinReal_fahrenheit] + -- We prove the forward direction. constructor · intro h + -- We derive `h'` stating that `f + 459.67 ≥ 0` + -- from the product being nonnegative with the + -- positive factor `5/9`. have h' : 0 ≤ f + (45967 : ℝ) / 100 := - (mul_nonneg_iff_of_pos_right (show (0 : ℝ) < 5 / 9 by norm_num)).1 h + (mul_nonneg_iff_of_pos_right + (show (0 : ℝ) < 5 / 9 by norm_num)).1 h + -- We conclude by linear arithmetic. QED for this + -- case. linarith + -- We prove the reverse direction. · intro h - have h' : 0 ≤ f + (45967 : ℝ) / 100 := by linarith + -- We derive `h'` stating that `f + 459.67 ≥ 0` + -- from the hypothesis. + have h' : 0 ≤ f + (45967 : ℝ) / 100 := by + linarith + -- We conclude by `mul_nonneg` since both factors + -- are nonnegative. QED for this case. + -- All cases have been proven. QED. exact mul_nonneg h' (by norm_num) end TemperatureScale namespace Temperature -/-- Convert an absolute temperature to a reading in an affine scale. -/ -noncomputable def toScale (T : Temperature) (s : TemperatureScale) : ℝ := +/-- Function for `Temperature`: + +Convert an absolute temperature to a reading in an affine scale. +-/ +noncomputable def toScale + (T : Temperature) (s : TemperatureScale) : ℝ := TemperatureScale.fromKelvinReal s (T : ℝ) -/-- Build an absolute temperature from an affine scale reading and a proof it is physically valid. -/ -noncomputable def ofScale (s : TemperatureScale) (x : ℝ) - (hx : 0 ≤ TemperatureScale.toKelvinReal s x) : Temperature := - Temperature.ofRealNonneg (TemperatureScale.toKelvinReal s x) hx +/-- Function for `Temperature`: + +Build an absolute temperature from an affine scale reading and a +proof it is physically valid. +-/ +noncomputable def ofScale (s : TemperatureScale) + (x : ℝ) + (hx : 0 ≤ TemperatureScale.toKelvinReal s x) : + Temperature := + Temperature.ofRealNonneg + (TemperatureScale.toKelvinReal s x) hx + +/-- Function for `Temperature`: + +Build an absolute temperature from an affine scale reading, +returning `none` below absolute zero. +-/ +noncomputable def ofScale? + (s : TemperatureScale) (x : ℝ) : + Option Temperature := + if hx : 0 ≤ TemperatureScale.toKelvinReal s x then + some (ofScale s x hx) + else none -/-- Build an absolute temperature from an affine scale reading, failing below absolute zero. -/ -noncomputable def ofScale? (s : TemperatureScale) (x : ℝ) : Option Temperature := - if hx : 0 ≤ TemperatureScale.toKelvinReal s x then some (ofScale s x hx) else none +/-- Function for `Temperature`: -/-- Convert an absolute temperature to Celsius. -/ +Convert an absolute temperature to Celsius. +-/ noncomputable def toCelsius (T : Temperature) : ℝ := toScale T TemperatureScale.celsius -/-- Convert an absolute temperature to Fahrenheit. -/ -noncomputable def toFahrenheit (T : Temperature) : ℝ := +/-- Function for `Temperature`: + +Convert an absolute temperature to Fahrenheit. +-/ +noncomputable def toFahrenheit + (T : Temperature) : ℝ := toScale T TemperatureScale.fahrenheit -/-- Build an absolute temperature from Celsius. -/ -noncomputable def ofCelsius (c : ℝ) (hc : (-(27315 : ℝ) / 100) ≤ c) : Temperature := - ofScale TemperatureScale.celsius c ((TemperatureScale.zero_le_toKelvinReal_celsius_iff c).2 hc) +/-- Function for `Temperature`: -/-- Build an absolute temperature from Fahrenheit. -/ -noncomputable def ofFahrenheit (f : ℝ) (hf : (-(45967 : ℝ) / 100) ≤ f) : Temperature := +Build an absolute temperature from Celsius. +-/ +noncomputable def ofCelsius (c : ℝ) + (hc : (-(27315 : ℝ) / 100) ≤ c) : Temperature := + ofScale TemperatureScale.celsius c + ((TemperatureScale.zero_le_toKelvinReal_celsius_iff + c).2 hc) + +/-- Function for `Temperature`: + +Build an absolute temperature from Fahrenheit. +-/ +noncomputable def ofFahrenheit (f : ℝ) + (hf : (-(45967 : ℝ) / 100) ≤ f) : Temperature := ofScale TemperatureScale.fahrenheit f - ((TemperatureScale.zero_le_toKelvinReal_fahrenheit_iff f).2 hf) + ((TemperatureScale.zero_le_toKelvinReal_fahrenheit_iff + f).2 hf) -/-- Build an absolute temperature from Celsius, returning `none` below absolute zero. -/ -noncomputable def ofCelsius? (c : ℝ) : Option Temperature := +/-- Function for `Temperature`: + +Build an absolute temperature from Celsius, returning `none` below +absolute zero. +-/ +noncomputable def ofCelsius? (c : ℝ) : + Option Temperature := ofScale? TemperatureScale.celsius c -/-- Build an absolute temperature from Fahrenheit, returning `none` below absolute zero. -/ -noncomputable def ofFahrenheit? (f : ℝ) : Option Temperature := +/-- Function for `Temperature`: + +Build an absolute temperature from Fahrenheit, returning `none` +below absolute zero. +-/ +noncomputable def ofFahrenheit? (f : ℝ) : + Option Temperature := ofScale? TemperatureScale.fahrenheit f +/-- Lemma for `Temperature`: + +Converting to a scale and back recovers the original reading. +-/ lemma toScale_ofScale (s : TemperatureScale) (x : ℝ) (hx : 0 ≤ TemperatureScale.toKelvinReal s x) : toScale (ofScale s x hx) s = x := by - simp [toScale, ofScale, Temperature.ofRealNonneg, Temperature.ofNNReal, - Temperature.toReal, TemperatureScale.fromKelvinReal_toKelvinReal] + -- We simplify using the definitions of `toScale`, + -- `ofScale`, `ofRealNonneg`, `ofNNReal`, `toReal`, + -- and the round-trip lemma + -- `fromKelvinReal_toKelvinReal`. QED. + simp [toScale, ofScale, Temperature.ofRealNonneg, + Temperature.ofNNReal, Temperature.toReal, + TemperatureScale.fromKelvinReal_toKelvinReal] -@[simp] -lemma toCelsius_zero : toCelsius (0 : Temperature) = (-(27315 : ℝ) / 100) := by - change TemperatureScale.fromKelvinReal TemperatureScale.celsius (((0 : Temperature).val : ℝ)) = - (-(27315 : ℝ) / 100) - have hzero : (((0 : Temperature).val : ℝ)) = 0 := by rfl - simp [hzero, TemperatureScale.fromKelvinReal, TemperatureScale.celsius] +/-- Simplification lemma for `Temperature`: +Absolute zero in Celsius is `-273.15`. +-/ @[simp] -lemma toFahrenheit_zero : toFahrenheit (0 : Temperature) = (-(45967 : ℝ) / 100) := by - change TemperatureScale.fromKelvinReal TemperatureScale.fahrenheit (((0 : Temperature).val : ℝ)) = - (-(45967 : ℝ) / 100) - have hzero : (((0 : Temperature).val : ℝ)) = 0 := by rfl - simp [hzero, TemperatureScale.fromKelvinReal, TemperatureScale.fahrenheit] - +lemma toCelsius_zero : + toCelsius (0 : Temperature) = + (-(27315 : ℝ) / 100) := by + -- We change the goal to unfold `toCelsius` and + -- `toScale` into `fromKelvinReal` applied to `0`. + change TemperatureScale.fromKelvinReal + TemperatureScale.celsius + (((0 : Temperature).val : ℝ)) = + (-(27315 : ℝ) / 100) + -- We derive that the real value of zero temperature + -- is `0`. + have hzero : (((0 : Temperature).val : ℝ)) = 0 := + by rfl + -- We simplify using `hzero` and the definitions of + -- `fromKelvinReal` and `celsius`. QED. + simp [hzero, TemperatureScale.fromKelvinReal, + TemperatureScale.celsius] + +/-- Simplification lemma for `Temperature`: + +Absolute zero in Fahrenheit is `-459.67`. +-/ +@[simp] +lemma toFahrenheit_zero : + toFahrenheit (0 : Temperature) = + (-(45967 : ℝ) / 100) := by + -- We change the goal to unfold `toFahrenheit` and + -- `toScale` into `fromKelvinReal` applied to `0`. + change TemperatureScale.fromKelvinReal + TemperatureScale.fahrenheit + (((0 : Temperature).val : ℝ)) = + (-(45967 : ℝ) / 100) + -- We derive that the real value of zero temperature + -- is `0`. + have hzero : (((0 : Temperature).val : ℝ)) = 0 := + by rfl + -- We simplify using `hzero` and the definitions of + -- `fromKelvinReal` and `fahrenheit`. QED. + simp [hzero, TemperatureScale.fromKelvinReal, + TemperatureScale.fahrenheit] + +/-- Simplification lemma for `Temperature`: + +`ofCelsius?` returns `none` below absolute zero. +-/ @[simp] -lemma ofCelsius?_below_absoluteZero : ofCelsius? ((-(27315 : ℝ) / 100) - 1) = none := by +lemma ofCelsius?_below_absoluteZero : + ofCelsius? ((-(27315 : ℝ) / 100) - 1) = + none := by + -- We simplify using the definitions of `ofCelsius?` + -- and `ofScale?`. simp [ofCelsius?, ofScale?] + -- We conclude by linear arithmetic, since the kelvin + -- value is negative below absolute zero. QED. linarith +/-- Simplification lemma for `Temperature`: + +`ofFahrenheit?` returns `none` below absolute zero. +-/ @[simp] -lemma ofFahrenheit?_below_absoluteZero : ofFahrenheit? ((-(45967 : ℝ) / 100) - 1) = none := by +lemma ofFahrenheit?_below_absoluteZero : + ofFahrenheit? ((-(45967 : ℝ) / 100) - 1) = + none := by + -- We simplify using the definitions of `ofFahrenheit?` + -- and `ofScale?`. simp [ofFahrenheit?, ofScale?] + -- We conclude by linear arithmetic, since the kelvin + -- value is negative below absolute zero. QED. linarith +/-- Lemma for `Temperature`: + +`-40` degrees Celsius equals `-40` degrees Fahrenheit. +-/ lemma minusForty_celsius_eq_minusForty_fahrenheit : - toFahrenheit (ofCelsius (-40) (by norm_num)) = (-40 : ℝ) := by + toFahrenheit (ofCelsius (-40) (by norm_num)) = + (-40 : ℝ) := by + -- We simplify using the definitions of `toFahrenheit`, + -- `toScale`, `ofCelsius`, and `ofScale`. simp [toFahrenheit, toScale, ofCelsius, ofScale] + -- We conclude by numerical computation. QED. norm_num end Temperature diff --git a/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean b/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean index 9d48a772c..9d6f975a7 100644 --- a/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean +++ b/PhysLean/Thermodynamics/Temperature/TemperatureUnits.lean @@ -6,151 +6,306 @@ Authors: Trong-Nghia Be, Tan-Phuoc-Hung Le, Joseph Tooby-Smith import Mathlib.Geometry.Manifold.Diffeomorph import PhysLean.SpaceAndTime.Time.Basic /-! - # Units on Temperature === TODO TIL THE END OF THE FILE -A unit of temperature interval corresponds to a choice of translationally-invariant -metric on the temperature manifold (to be defined diffeomorphic to `ℝ≥0`). -Such a choice is (non-canonically) equivalent to a -choice of positive real number. We define the type `TemperatureUnit` to be equivalent to the -positive reals. - -On `TemperatureUnit` there is an instance of division giving a real number, corresponding to the -ratio of the two interval scales. +A unit of temperature interval corresponds to a choice of +translationally-invariant metric on the temperature manifold (to be +defined diffeomorphic to `ℝ≥0`). Such a choice is (non-canonically) +equivalent to a choice of positive real number. We define the type +`TemperatureUnit` to be equivalent to the positive reals. -To define specific temperature units, we first state the existence of a -a given temperature unit, and then construct all other temperature units from it. -We choose to state the -existence of the temperature unit of kelvin, and construct all other temperature units from that. +On `TemperatureUnit` there is an instance of division giving a real +number, corresponding to the ratio of the two interval scales. +To define specific temperature units, we first state the existence of +a given temperature unit, and then construct all other temperature +units from it. We choose to state the existence of the temperature +unit of kelvin, and construct all other temperature units from that. -/ open NNReal -/-- The choices of translationally-invariant metrics on the temperature-manifold. - Such a choice corresponds to a multiplicative choice of unit scale for temperature intervals. -/ +/-- The type `TemperatureUnit` represents a choice of + translationally-invariant metric on the temperature-manifold, + corresponding to a multiplicative choice of unit scale for + temperature intervals. + - `val` of type `ℝ`: The underlying scale of the unit. + - `property` of type `0 < val`: Proof that the scale is strictly + positive. +-/ structure TemperatureUnit where /-- The underlying scale of the unit. -/ val : ℝ + /-- Proof that the scale is strictly positive. -/ property : 0 < val namespace TemperatureUnit +/-- Simplification lemma for `TemperatureUnit`: + +The value of a temperature unit is nonzero. +-/ @[simp] lemma val_ne_zero (x : TemperatureUnit) : x.val ≠ 0 := by + -- Since `x.val > 0` (by `x.property`), it follows that + -- `x.val ≠ 0` by `Ne.symm` applied to `ne_of_lt x.property`. + -- QED. exact Ne.symm (ne_of_lt x.property) -lemma val_pos (x : TemperatureUnit) : 0 < x.val := x.property +/-- Lemma for `TemperatureUnit`: +The value of a temperature unit is strictly positive. +-/ +lemma val_pos (x : TemperatureUnit) : 0 < x.val := + x.property + +/-- Default instance for `TemperatureUnit`, set to scale `1`. +-/ instance : Inhabited TemperatureUnit where default := ⟨1, by norm_num⟩ /-! - ## Division of TemperatureUnit +-/ +/-- Division of two `TemperatureUnit` values, yielding a nonnegative +ratio in `ℝ≥0`. -/ +noncomputable instance : + HDiv TemperatureUnit TemperatureUnit ℝ≥0 where + hDiv x t := + ⟨x.val / t.val, + div_nonneg (le_of_lt x.val_pos) (le_of_lt t.val_pos)⟩ -noncomputable instance : HDiv TemperatureUnit TemperatureUnit ℝ≥0 where - hDiv x t := ⟨x.val / t.val, div_nonneg (le_of_lt x.val_pos) (le_of_lt t.val_pos)⟩ +/-- Lemma for `TemperatureUnit`: +Division unfolds to the ratio of underlying values. +-/ lemma div_eq_val (x y : TemperatureUnit) : - x / y = (⟨x.val / y.val, div_nonneg (le_of_lt x.val_pos) (le_of_lt y.val_pos)⟩ : ℝ≥0) := rfl + x / y = + (⟨x.val / y.val, + div_nonneg (le_of_lt x.val_pos) + (le_of_lt y.val_pos)⟩ : ℝ≥0) := rfl + +/-- Simplification lemma for `TemperatureUnit`: +The division of two temperature units is nonzero. +-/ @[simp] -lemma div_ne_zero (x y : TemperatureUnit) : ¬ x / y = (0 : ℝ≥0) := by +lemma div_ne_zero (x y : TemperatureUnit) : + ¬ x / y = (0 : ℝ≥0) := by + -- We rewrite the goal using the definition of division + -- from `div_eq_val`, which unfolds the division into the + -- ratio of underlying values. rw [div_eq_val] + -- We refine the goal using `coe_ne_zero.mp`, which + -- reduces the nonzero condition on `ℝ≥0` to a condition + -- on the underlying `ℝ` values. refine coe_ne_zero.mp ?_ + -- We simplify to conclude, since `x.val / y.val ≠ 0` + -- follows from both values being strictly positive. QED. simp +/-- Simplification lemma for `TemperatureUnit`: + +The division of two temperature units is strictly positive. +-/ @[simp] -lemma div_pos (x y : TemperatureUnit) : (0 : ℝ≥0) < x/ y := by +lemma div_pos (x y : TemperatureUnit) : + (0 : ℝ≥0) < x / y := by + -- We apply `lt_of_le_of_ne` to show strict positivity + -- from nonnegativity and the fact that the division is + -- nonzero. apply lt_of_le_of_ne + -- `case ha`: The goal is `⊢ 0 ≤ x / y`, which is true + -- since `x / y : ℝ≥0` is nonnegative by definition. + -- QED for this case. · exact zero_le (x / y) + -- `case hb`: The goal is `⊢ 0 ≠ x / y`, which follows + -- from `div_ne_zero x y` by symmetry. QED for this case. + -- All cases have been proven. QED. · exact Ne.symm (div_ne_zero x y) +/-- Simplification lemma for `TemperatureUnit`: + +Dividing a temperature unit by itself yields `1`. +-/ @[simp] lemma div_self (x : TemperatureUnit) : x / x = (1 : ℝ≥0) := by + -- We simplify using the definition of division and the + -- fact that `x.val ≠ 0`. QED. simp [div_eq_val, x.val_ne_zero] +/-- Lemma for `TemperatureUnit`: + +Division is the inverse of the reverse division. +-/ lemma div_symm (x y : TemperatureUnit) : x / y = (y / x)⁻¹ := NNReal.eq <| by + -- We rewrite both sides using `div_eq_val` and + -- `inv_eq_one_div` to express them in terms of + -- underlying values. rw [div_eq_val, inv_eq_one_div, div_eq_val] + -- We simplify to conclude, since the algebraic identity + -- `x / y = (y / x)⁻¹` holds for positive reals. QED. simp +/-- Simplification lemma for `TemperatureUnit`: + +Chain rule for division: `(x / y) * (y / z) = x / z` when coerced +to `ℝ`. +-/ @[simp] lemma div_mul_div_coe (x y z : TemperatureUnit) : - (x / y : ℝ) * (y /z : ℝ) = x /z := by + (x / y : ℝ) * (y / z : ℝ) = x / z := by + -- We simplify using the definition of division. simp [div_eq_val] + -- We apply `field_simp` to clear denominators and + -- conclude by algebraic simplification. QED. field_simp /-! - ## The scaling of a temperature unit - -/ -/-- The scaling of a temperature unit by a positive real. -/ -def scale (r : ℝ) (x : TemperatureUnit) (hr : 0 < r := by norm_num) : TemperatureUnit := +/-- Function for `TemperatureUnit`: + +Scale a temperature unit by a positive real number. +-/ +def scale (r : ℝ) (x : TemperatureUnit) + (hr : 0 < r := by norm_num) : TemperatureUnit := ⟨r * x.val, mul_pos hr x.val_pos⟩ +/-- Simplification lemma for `TemperatureUnit`: + +Scaling a unit and dividing by the original yields the scale factor. +-/ @[simp] -lemma scale_div_self (x : TemperatureUnit) (r : ℝ) (hr : 0 < r) : +lemma scale_div_self (x : TemperatureUnit) (r : ℝ) + (hr : 0 < r) : scale r x hr / x = (⟨r, le_of_lt hr⟩ : ℝ≥0) := by + -- We simplify using the definitions of `scale` and + -- `div_eq_val`. QED. simp [scale, div_eq_val] +/-- Simplification lemma for `TemperatureUnit`: + +Dividing a unit by its scaled version yields the reciprocal of the +scale factor. +-/ @[simp] -lemma self_div_scale (x : TemperatureUnit) (r : ℝ) (hr : 0 < r) : - x / scale r x hr = (⟨1/r, _root_.div_nonneg (by simp) (le_of_lt hr)⟩ : ℝ≥0) := by +lemma self_div_scale (x : TemperatureUnit) (r : ℝ) + (hr : 0 < r) : + x / scale r x hr = + (⟨1 / r, + _root_.div_nonneg (by simp) + (le_of_lt hr)⟩ : ℝ≥0) := by + -- We simplify using the definitions of `scale` and + -- `div_eq_val`. simp [scale, div_eq_val] + -- We apply extensionality to reduce the goal to + -- equality of underlying values. ext + -- We simplify the coercion from `ℝ≥0` to `ℝ`. simp only [coe_mk] + -- We apply `field_simp` to clear denominators and + -- conclude by algebraic simplification. QED. field_simp +/-- Simplification lemma for `TemperatureUnit`: + +Scaling by `1` is the identity. +-/ @[simp] -lemma scale_one (x : TemperatureUnit) : scale 1 x = x := by +lemma scale_one (x : TemperatureUnit) : + scale 1 x = x := by + -- We simplify using the definition of `scale`, since + -- `1 * x.val = x.val`. QED. simp [scale] +/-- Simplification lemma for `TemperatureUnit`: + +The ratio of two scaled units factors into the product of scale +ratios and unit ratios. +-/ @[simp] -lemma scale_div_scale (x1 x2 : TemperatureUnit) {r1 r2 : ℝ} (hr1 : 0 < r1) (hr2 : 0 < r2) : - scale r1 x1 hr1 / scale r2 x2 hr2 = (⟨r1, le_of_lt hr1⟩ / ⟨r2, le_of_lt hr2⟩) * (x1 / x2) := by +lemma scale_div_scale (x1 x2 : TemperatureUnit) + {r1 r2 : ℝ} (hr1 : 0 < r1) (hr2 : 0 < r2) : + scale r1 x1 hr1 / scale r2 x2 hr2 = + (⟨r1, le_of_lt hr1⟩ / ⟨r2, le_of_lt hr2⟩) * + (x1 / x2) := by + -- We refine the goal using `NNReal.eq`, which reduces + -- equality of `ℝ≥0` values to equality of their + -- underlying `ℝ` values. refine NNReal.eq ?_ + -- We simplify using the definitions of `scale` and + -- `div_eq_val`. simp [scale, div_eq_val] + -- We apply `field_simp` to clear denominators and + -- conclude by algebraic simplification. QED. field_simp +/-- Simplification lemma for `TemperatureUnit`: + +Double scaling is equivalent to scaling by the product. +-/ @[simp] -lemma scale_scale (x : TemperatureUnit) (r1 r2 : ℝ) (hr1 : 0 < r1) (hr2 : 0 < r2) : - scale r1 (scale r2 x hr2) hr1 = scale (r1 * r2) x (mul_pos hr1 hr2) := by +lemma scale_scale (x : TemperatureUnit) (r1 r2 : ℝ) + (hr1 : 0 < r1) (hr2 : 0 < r2) : + scale r1 (scale r2 x hr2) hr1 = + scale (r1 * r2) x (mul_pos hr1 hr2) := by + -- We simplify using the definition of `scale`. simp [scale] + -- We conclude by the algebraic identity + -- `r1 * (r2 * x.val) = (r1 * r2) * x.val`. QED. ring /-! - ## Specific choices of temperature units -To define a specific temperature units. -We first define the notion of a kelvin to correspond to the temperature unit with underlying value -equal to `1`. This is really down to a choice in the isomorphism between the set of metrics -on the temperature manifold and the positive reals. - -Once we have defined kelvin, we can define other temperature units by scaling kelvin. +To define specific temperature units, we first define the notion of +a kelvin to correspond to the temperature unit with underlying value +equal to `1`. This is really down to a choice in the isomorphism +between the set of metrics on the temperature manifold and the +positive reals. +Once we have defined kelvin, we can define other temperature units +by scaling kelvin. -/ -/-- The definition of a temperature unit of kelvin. -/ +/-- Function for `TemperatureUnit`: + +The definition of a temperature unit of kelvin. +-/ def kelvin : TemperatureUnit := ⟨1, by norm_num⟩ -/-- The temperature unit of degrees nanokelvin (10^(-9) kelvin). -/ -noncomputable def nanokelvin : TemperatureUnit := scale (1e-9) kelvin +/-- Function for `TemperatureUnit`: + +The temperature unit of degrees nanokelvin (`10^(-9) kelvin`). +-/ +noncomputable def nanokelvin : TemperatureUnit := + scale (1e-9) kelvin + +/-- Function for `TemperatureUnit`: + +The temperature unit of degrees microkelvin (`10^(-6) kelvin`). +-/ +noncomputable def microkelvin : TemperatureUnit := + scale (1e-6) kelvin + +/-- Function for `TemperatureUnit`: -/-- The temperature unit of degrees microkelvin (10^(-6) kelvin). -/ -noncomputable def microkelvin : TemperatureUnit := scale (1e-6) kelvin +The temperature unit of degrees millikelvin (`10^(-3) kelvin`). +-/ +noncomputable def millikelvin : TemperatureUnit := + scale (1e-3) kelvin -/-- The temperature unit of degrees millikelvin (10^(-3) kelvin). -/ -noncomputable def millikelvin : TemperatureUnit := scale (1e-3) kelvin +/-- Function for `TemperatureUnit`: -/-- The temperature unit of degrees rankine ((5/9) of a kelvin). -/ -noncomputable def rankine : TemperatureUnit := scale (5 / 9) kelvin +The temperature unit of degrees rankine (`(5/9)` of a kelvin). +-/ +noncomputable def rankine : TemperatureUnit := + scale (5 / 9) kelvin end TemperatureUnit From 9afcd9aee28ccb97a14d4cb0cde8a73cfd1f93f2 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 09:31:46 +0000 Subject: [PATCH 10/12] feat(thermodynamics): add temperature scales import and clean up code * Added import for `TemperatureScales` in `PhysLean.lean`. * Reformatted code for better readability in several lemmas across temperature-related files. * Removed unnecessary blank lines to improve code clarity. --- PhysLean.lean | 1 + .../CanonicalEnsemble/Basic.lean | 3 ++- PhysLean/Thermodynamics/Temperature/Basic.lean | 5 ++--- PhysLean/Thermodynamics/Temperature/Calculus.lean | 12 ++++++------ PhysLean/Thermodynamics/Temperature/Convergence.lean | 1 - PhysLean/Thermodynamics/Temperature/Regularity.lean | 8 ++++---- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/PhysLean.lean b/PhysLean.lean index e4a5d5add..d4731e5aa 100644 --- a/PhysLean.lean +++ b/PhysLean.lean @@ -387,6 +387,7 @@ import PhysLean.Thermodynamics.Temperature.Calculus import PhysLean.Thermodynamics.Temperature.Convergence import PhysLean.Thermodynamics.Temperature.Regularity import PhysLean.Thermodynamics.Temperature.TemperatureUnits +import PhysLean.Thermodynamics.Temperature.TemperatureScales import PhysLean.Units.Basic import PhysLean.Units.Dimension import PhysLean.Units.Examples diff --git a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean index 82bd5e9ad..1d16866b4 100644 --- a/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean +++ b/PhysLean/StatisticalMechanics/CanonicalEnsemble/Basic.lean @@ -370,7 +370,8 @@ lemma μBolt_ne_zero_of_μ_ne_zero (T : Temperature) (h : 𝓒.μ ≠ 0) : simp [μBolt] at ⊢ h rw [Measure.ext_iff'] at ⊢ h simp only [Measure.coe_zero, Pi.zero_apply] - have hs : {x | ENNReal.ofReal (rexp (-(T.toReal⁻¹ * Constants.kB⁻¹ * 𝓒.energy x))) ≠ 0} = Set.univ := by + have hs : {x | ENNReal.ofReal + (rexp (-(T.toReal⁻¹ * Constants.kB⁻¹ * 𝓒.energy x))) ≠ 0} = Set.univ := by ext i simp only [ne_eq, ENNReal.ofReal_eq_zero, not_le, Set.mem_setOf_eq, Set.mem_univ, iff_true] exact exp_pos _ diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index ddb530644..3335de136 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -184,7 +184,7 @@ The definition of `β T` unfolds to its explicit formula in terms of `kB` and `T -/ @[simp] lemma β_eq (T : Temperature) : β T = - ⟨1 / (kB * (T : ℝ)), by + ⟨1 / (kB * (T : ℝ)), by apply div_nonneg · exact zero_le_one · apply mul_nonneg @@ -199,7 +199,7 @@ lemma β_eq (T : Temperature) : β T = Coercing `β T` from `ℝ≥0` to `ℝ` gives the explicit formula `1 / (kB * (T : ℝ))`. -/ @[simp] -lemma β_toReal (T : Temperature) : (β T : ℝ) = (1 : ℝ) / (kB * (T : ℝ)) := by +lemma β_toReal (T : Temperature) : (β T : ℝ) = (1 : ℝ) / (kB * (T : ℝ)) := by -- We rewrite the goal using the definition of `β` from the previous lemma `β_eq`, which gives us -- `⊢ ↑⟨1 / (kB * T.toReal), ⋯⟩ = 1 / (kB * T.toReal)`, where `↑` denotes the coercion from `ℝ≥0` -- to `ℝ`, and `⋯` represents the proof of non-negativity that we can ignore since it does not @@ -211,7 +211,6 @@ lemma β_toReal (T : Temperature) : (β T : ℝ) = (1 : ℝ) / (kB * (T : ℝ)) -- equality (`rfl`). QED. rfl - /-- Function for `Temperature`: Calculate the temperature associated with a given inverse temperature `β`. diff --git a/PhysLean/Thermodynamics/Temperature/Calculus.lean b/PhysLean/Thermodynamics/Temperature/Calculus.lean index 37aa346c9..7586e075e 100644 --- a/PhysLean/Thermodynamics/Temperature/Calculus.lean +++ b/PhysLean/Thermodynamics/Temperature/Calculus.lean @@ -44,7 +44,7 @@ noncomputable def βFromReal (t : ℝ) : ℝ := ((Temperature.ofNNReal (Real.toN Explicit closed-form for `βFromReal t` when `t > 0`: `βFromReal t = 1 / (kB * t)`. -/ lemma β_fun_T_formula (t : ℝ) (h_t_pos : 0 < t) : - βFromReal t = (1 : ℝ) / (kB * t) := by + βFromReal t = (1 : ℝ) / (kB * t) := by -- We derive `h_t_nonneg : 0 ≤ t` from `h_t_pos` by weakening strict -- inequality to non-strict inequality. have h_t_nonneg : (0 : ℝ) ≤ t := h_t_pos.le @@ -53,7 +53,7 @@ lemma β_fun_T_formula (t : ℝ) (h_t_pos : 0 < t) : -- by simplifying using the definitions of `β`, `ofNNReal`, `toReal`, -- and the fact that `Real.toNNReal t = t` when `t ≥ 0`. have h_beta_formula : - ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = (1 : ℝ) / (kB * t) := by + ((Temperature.ofNNReal (Real.toNNReal t)).β : ℝ) = (1 : ℝ) / (kB * t) := by simp [Temperature.β, Temperature.ofNNReal, Temperature.toReal, Real.toNNReal_of_nonneg h_t_nonneg, one_div, mul_comm] -- We conclude by simplifying the definition of `βFromReal` and @@ -64,7 +64,7 @@ lemma β_fun_T_formula (t : ℝ) (h_t_pos : 0 < t) : On the interval `(0, ∞)`, `βFromReal t` equals `1 / (kB * t)`. -/ -lemma β_fun_T_eq_on_Ioi : EqOn βFromReal (fun t : ℝ => (1 : ℝ) / (kB * t)) (Set.Ioi 0) := by +lemma β_fun_T_eq_on_Ioi : EqOn βFromReal (fun t : ℝ => (1 : ℝ) / (kB * t)) (Set.Ioi 0) := by -- We introduce `t : ℝ` and the hypothesis -- `h_t_pos : t ∈ Set.Ioi 0` (i.e. `0 < t`) from the goal. intro t h_t_pos @@ -84,7 +84,7 @@ lemma deriv_β_wrt_T (T : Temperature) (h_T_pos : 0 < T.val) : HasDerivWithinAt -- We define `f : ℝ → ℝ` as the explicit formula -- `f t = 1 / (kB * t)`, which is the closed form of -- `βFromReal` on `(0, ∞)`. - let f : ℝ → ℝ := fun t => (1 : ℝ) / (kB * t) + let f : ℝ → ℝ := fun t => (1 : ℝ) / (kB * t) -- We derive `h_eq_on : EqOn βFromReal f (Set.Ioi 0)` -- using `β_fun_T_eq_on_Ioi`, which states that -- `βFromReal` and `f` agree on `(0, ∞)`. @@ -190,12 +190,12 @@ lemma chain_rule_T_β {F : ℝ → ℝ} {F' : ℝ} mul_pos kB_pos h_t_pos -- We derive `h_quotient_pos : 0 < 1 / (kB * t)` using -- `one_div_pos.mpr h_kB_mul_t_pos`. - have h_quotient_pos : 0 < (1 : ℝ) / (kB * t) := + have h_quotient_pos : 0 < (1 : ℝ) / (kB * t) := one_div_pos.mpr h_kB_mul_t_pos -- We derive `h_βFromReal_eq` which states that -- `βFromReal t = 1 / (kB * t)` on `(0, ∞)`. have h_βFromReal_eq : - βFromReal t = (1 : ℝ) / (kB * t) := + βFromReal t = (1 : ℝ) / (kB * t) := β_fun_T_eq_on_Ioi h_t_pos -- We conclude by rewriting `βFromReal t` with -- `h_βFromReal_eq` and applying `h_quotient_pos`. QED. diff --git a/PhysLean/Thermodynamics/Temperature/Convergence.lean b/PhysLean/Thermodynamics/Temperature/Convergence.lean index 08f91ef28..4039f3961 100644 --- a/PhysLean/Thermodynamics/Temperature/Convergence.lean +++ b/PhysLean/Thermodynamics/Temperature/Convergence.lean @@ -140,7 +140,6 @@ private lemma tendsto_const_inv_mul_at_bound_lt_epsilon (a ε : ℝ) (h_a_pos : -- Finally, we conclude that `⊢ 0 < a * ε` is true by `h_product_pos`. QED. exact h_product_pos - /-- Helper lemma for `Temperature`: Conversion from nonnegative inequality to metric space distance. diff --git a/PhysLean/Thermodynamics/Temperature/Regularity.lean b/PhysLean/Thermodynamics/Temperature/Regularity.lean index 9d4572acd..a5eb1fc9f 100644 --- a/PhysLean/Thermodynamics/Temperature/Regularity.lean +++ b/PhysLean/Thermodynamics/Temperature/Regularity.lean @@ -60,7 +60,7 @@ private lemma ofβ_real_nonneg (b : ℝ≥0) : 0 ≤ (1 : ℝ) / (kB * (b : ℝ) /-- Helper lemma for `Temperature`: -Continuity at a positive point for the real formula `(t : ℝ) ↦ (1 : ℝ) / (kB * t)`. +Continuity at a positive point for the real formula `(t : ℝ) ↦ (1 : ℝ) / (kB * t)`. -/ private lemma ofβ_realExpr_continuousAt_real (x : ℝ≥0) (h_x_pos : 0 < x) : ContinuousAt (fun (t : ℝ) => (1 : ℝ) / (kB * t)) (x : ℝ) := by @@ -92,9 +92,9 @@ private lemma ofβ_realExpr_continuousAt_nnreal (x : ℝ≥0) (h_x_pos : 0 < x) -- We define `f : ℝ≥0 → ℝ` as `f (b : ℝ≥0) := (1 : ℝ) / (kB * b)`. -- This is the same as the function in the goal, but we give it a name for clarity. let f : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (1 : ℝ) / (kB * b) - -- We define `g : ℝ → ℝ` as `g (t : ℝ) := (1 : ℝ) / (kB * t)`. + -- We define `g : ℝ → ℝ` as `g (t : ℝ) := (1 : ℝ) / (kB * t)`. -- This is the same formula as `f`, but defined on `ℝ`. - let g : ℝ → ℝ := fun (t : ℝ) => (1 : ℝ) / (kB * t) + let g : ℝ → ℝ := fun (t : ℝ) => (1 : ℝ) / (kB * t) -- We define `h : ℝ≥0 → ℝ` as `h (b : ℝ≥0) := (b : ℝ)`. -- This is the coercion from `ℝ≥0` to `ℝ`. let h : ℝ≥0 → ℝ := fun (b : ℝ≥0) => (b : ℝ) @@ -201,7 +201,7 @@ lemma ofβ_differentiableOn : -- We refine the goal using `DifferentiableOn.congr`, which allows us to prove differentiability -- by showing that the function is equal to a simpler function that we can easily differentiate. -- We now have two cases: - refine DifferentiableOn.congr (f := fun (x : ℝ) => (1 : ℝ) / (kB * x)) ?_ ?_ + refine DifferentiableOn.congr (f := fun (x : ℝ) => (1 : ℝ) / (kB * x)) ?_ ?_ -- `case refine_1` : The goal is `⊢ DifferentiableOn ℝ (fun x => 1 / (kB * x)) (Set.Ioi 0)`. -- We further refine this using `DifferentiableOn.fun_div`, which requires us -- to prove differentiability of the numerator and denominator separately, From 27e7739cd047ff4ce7061750c4a3b8cd2c70f22c Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Tue, 24 Feb 2026 10:19:05 +0000 Subject: [PATCH 11/12] style(physlean): reorder imports --- PhysLean.lean | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PhysLean.lean b/PhysLean.lean index d4731e5aa..564455134 100644 --- a/PhysLean.lean +++ b/PhysLean.lean @@ -386,8 +386,8 @@ import PhysLean.Thermodynamics.Temperature.Basic import PhysLean.Thermodynamics.Temperature.Calculus import PhysLean.Thermodynamics.Temperature.Convergence import PhysLean.Thermodynamics.Temperature.Regularity -import PhysLean.Thermodynamics.Temperature.TemperatureUnits import PhysLean.Thermodynamics.Temperature.TemperatureScales +import PhysLean.Thermodynamics.Temperature.TemperatureUnits import PhysLean.Units.Basic import PhysLean.Units.Dimension import PhysLean.Units.Examples From daefceec6728515095b0d6ab2a55b713718e5bf0 Mon Sep 17 00:00:00 2001 From: Curly-Howard-Chungus Correspondence | Lamport-Cabot-Codd-Backus-Naur Form Date: Wed, 25 Feb 2026 03:26:03 +0000 Subject: [PATCH 12/12] docs(temperature): minor docstring edit --- PhysLean/Thermodynamics/Temperature/Basic.lean | 8 -------- 1 file changed, 8 deletions(-) diff --git a/PhysLean/Thermodynamics/Temperature/Basic.lean b/PhysLean/Thermodynamics/Temperature/Basic.lean index 3335de136..a75007872 100644 --- a/PhysLean/Thermodynamics/Temperature/Basic.lean +++ b/PhysLean/Thermodynamics/Temperature/Basic.lean @@ -29,7 +29,6 @@ For calculus relating T and β, see open NNReal /-- The type `Temperature` represents absolute thermodynamic temperature in kelvin. - - `val` of type `ℝ≥0`: The nonnegative real value of the temperature. -/ structure Temperature where /-- The nonnegative real value of the temperature. -/ @@ -149,13 +148,6 @@ Calculate the inverse temperature `β` corresponding to a given temperature `T`. 1. This has dimensions equivalent to `Energy` to the power `-1`. Refer to the concept of "thermodynamic beta" in thermodynamics for more details. - -2. Currently this formula allows for "non-negative" temperatures, which includes absolute zero in -the denominator. In physical terms, absolute zero is a limit that cannot be reached, and the formula -for `β` is not well-defined at `T = 0`. Therefore, while the type `Temperature` allows for `T = 0`, -we should refactor this definition in the future to exclude absolute zero, either by refining the -domain or by defining `β` as a partial function that is only defined for strictly positive -temperatures. -/ noncomputable def β (T : Temperature) : ℝ≥0 := -- Given the formula `(1 / (kB * (T : ℝ))) : ℝ≥0`, we need to show that this is non-negative to