Zulip Chat Archive
Stream: PhysLean
Topic: QM reflectionless potential
Afiq Hatta (Jul 31 2025 at 11:47):
Hey folks I'm starting to work on the reflectionless potential just to get myself acquianted with lean
Afiq Hatta (Jul 31 2025 at 11:47):
@Joseph Tooby-Smith
Joseph Tooby-Smith (Jul 31 2025 at 11:52):
Just for some context Afiq and I have being discussing this 'offline', so this is a place to discuss things related to the QM reflectionless potential in the open.
Afiq Hatta (Aug 01 2025 at 09:44):
hey @Joseph Tooby-Smith was just thinking of an easy next step - i'm guessing defining the creation and annihilation operators in the paper?
Joseph Tooby-Smith (Aug 01 2025 at 10:00):
Yes, this seems like a good next step to me, that or writing down the full Hamiltonian as a operator on ordinary functions
Afiq Hatta (Aug 04 2025 at 07:58):
@Joseph Tooby-Smith we can discuss this on the call later but I need to use the position and momentum operators, for the creation / annihilation stuff - I guess those are good to import from the Operators module?
Joseph Tooby-Smith (Aug 04 2025 at 08:03):
Yep, it is best to import them from the operators module, if you need any properties of them which aren't yet proven, these should go into the operators module.
Afiq Hatta (Aug 04 2025 at 08:03):
awesomesauce
Afiq Hatta (Aug 04 2025 at 08:42):
pull request made
Afiq Hatta (Aug 04 2025 at 08:49):
i guess the next dumb thing to do would be to prove creation operator is conjugate to the annihilation one!
Joseph Tooby-Smith (Aug 04 2025 at 09:00):
This might be tricky, but it is certainly doable. It is tricky because by conjugate here you really mean hermitian conjugate (if you don't then it's not true anyway).
The way your operators are currently defined, they are defined on the normal functions from β β β, but to define their hermitian conjugate you need them defined on the Hilbert space (at least part of the Hilbert space).
An example of this type of thing is done in the momentumOperator file, see e.g. the lemma
momentumOperatorUnbounded_isSelfAdjoint
In particular, in addition to creationOperator you should also define creationOperatorSchwartz and creationOperatorUnbounded copying what is in the momentum operator module.
Afiq Hatta (Aug 04 2025 at 09:30):
agreed to all - will get cracking
Afiq Hatta (Aug 04 2025 at 10:34):
To do:
- do the Schwartz Space operator versions
Afiq Hatta (Aug 04 2025 at 20:16):
so @Joseph Tooby-Smith to even create these Schwartz versions of creation and annihilation operators, we need to prove that they're linear right?
Afiq Hatta (Aug 04 2025 at 20:17):
ie what you did here:
/-- The parity operator on the Schwartz maps is defined as the linear map from
`π’(β, β)` to itself, such that `Ο` is taken to `fun x => - I β * Ο' x`. -/
def momentumOperatorSchwartz : π’(β, β) βL[β] π’(β, β) where
toFun Ο := (- Complex.I * β) β’ SchwartzMap.derivCLM β Ο
map_add' Ο1 Ο2 := by
simp only [neg_mul, map_add, smul_add, neg_smul]
map_smul' a Ο := by
simp only [neg_mul, map_smul, neg_smul, RingHom.id_apply]
rw [smul_comm]
simp
cont := by fun_prop
Afiq Hatta (Aug 04 2025 at 20:20):
in the case of the creation and annihilation operators, would the cleanest way be to prove that the tanh operator is Schwartz, and then since their linear combinations of the tanh operator and the momentum operator => creation and annihilation operators are aalso schwartz
Joseph Tooby-Smith (Aug 04 2025 at 20:22):
Afiq Hatta said:
so Joseph Tooby-Smith to even create these Schwartz versions of creation and annihilation operators, we need to prove that they're linear right?
Yes, exactly, the βL[β] is the notation for a continuous linear map.
Joseph Tooby-Smith (Aug 04 2025 at 20:22):
Afiq Hatta said:
in the case of the creation and annihilation operators, would the cleanest way be to prove that the tanh operator is Schwartz, and then since their linear combinations of the tanh operator and the momentum operator => creation and annihilation operators are aalso schwartz
Yep that sounds like the best way to me.
Afiq Hatta (Aug 04 2025 at 20:45):
really dumb question
I know what is required for a continuous linear map, but how in general can i find the 'requirements' needed to define a particular structure?
is it the 'fields' section of what i get when i type ```
#print ContinuousLinearMap
structure ContinuousLinearMap.{u_1, u_2, u_3, u_4} {R : Type u_1} {S : Type u_2} [Semiring R] [Semiring S] (Ο : R β+* S)
(M : Type u_3) [TopologicalSpace M] [AddCommMonoid M] (Mβ : Type u_4) [TopologicalSpace Mβ] [AddCommMonoid Mβ]
[Module R M] [Module S Mβ] : Type (max u_3 u_4)
number of parameters: 13
parents:
ContinuousLinearMap.toLinearMap : M βββ[Ο] Mβ
fields:
AddHom.toFun : M β Mβ
AddHom.map_add' : β (x y : M), (βself).toFun (x + y) = (βself).toFun x + (βself).toFun y
MulActionHom.map_smul' : β (m : R) (x : M), (βself).toFun (m β’ x) = Ο m β’ (βself).toFun x
ContinuousLinearMap.cont : Continuous (βself).toFun := by
continuity
constructor:
ContinuousLinearMap.mk.{u_1, u_2, u_3, u_4} {R : Type u_1} {S : Type u_2} [Semiring R] [Semiring S] {Ο : R β+* S}
{M : Type u_3} [TopologicalSpace M] [AddCommMonoid M] {Mβ : Type u_4} [TopologicalSpace Mβ] [AddCommMonoid Mβ]
[Module R M] [Module S Mβ] (toLinearMap : M βββ[Ο] Mβ) (cont : Continuous toLinearMap.toFun := by continuity) :
M βSL[Ο] Mβ
field notation resolution order:
ContinuousLinearMap, LinearMap, AddHom, MulActionHom
Joseph Tooby-Smith (Aug 05 2025 at 05:39):
The way I do it is just start typing the definition, e.g.
def momentumOperatorSchwartz : π’(β, β) βL[β] π’(β, β) where
This will then give an error on the where because things are incomplete, and the error will list the fields needed.
Afiq Hatta (Aug 05 2025 at 08:59):
got it - thanks Joe for the flag
Afiq Hatta (Aug 10 2025 at 11:15):
really dumb question @Joseph Tooby-Smith but i can't get this to work - just even the definition part
noncomputable def tanhOperatorSchwartz : π’(β, β) βL[β] π’(β, β) where
toFun Ο := (fun x β¦ (Real.tanh (Q.ΞΊ * x) : β) * Ο x)
I am getting this error
type mismatch
fun x => β(tanh (Q.ΞΊ * x)) * Ο x
has type
β β β : Type
but is expected to have type
π’(β, β) : Type
Afiq Hatta (Aug 10 2025 at 11:16):
I don't see anything wrong with the definition itself - where am I falling over?
Afiq Hatta (Aug 10 2025 at 11:18):
am i not 'casting' the function correctly here?
Kenny Lau (Aug 10 2025 at 11:36):
@Afiq Hatta you're misinterpreting what toFun means
Kenny Lau (Aug 10 2025 at 11:36):
toFun requires you to make a function π’(β, β) -> π’(β, β) first
Kenny Lau (Aug 10 2025 at 11:36):
and prove that this function is linear and continuous
Kenny Lau (Aug 10 2025 at 11:38):
it does not mean, first make a function π’(β, β) -> (β -> β), and prove that every result is Schwarz
Kenny Lau (Aug 10 2025 at 11:38):
in other words, you need two layers of toFun here
Afiq Hatta (Aug 10 2025 at 11:42):
ahhh i hear you - i need to first prove that pointwise multiplication by tanh ( x ) is itself - π’(β, β) -> π’(β, β) (by boundedness, continuity) ? @Kenny Lau
Afiq Hatta (Aug 10 2025 at 11:43):
apologies - beginner here!! :p
Afiq Hatta (Aug 10 2025 at 12:03):
if thats the case - then there should be an inductive proof that all derivatives of (tanh (x) psi (x) ) don't blow up - i don't think theres a general result that we can apply here from other places in the library?
Kenny Lau (Aug 10 2025 at 12:11):
what's the maths proof?
Afiq Hatta (Aug 10 2025 at 12:11):
writing it down now...
Kenny Lau (Aug 10 2025 at 12:12):
I feel like it should follow from tanh(x) itself being Schwartz?
Afiq Hatta (Aug 10 2025 at 12:16):
its not though right, since -> +- 1 at +- infty?
Kenny Lau (Aug 10 2025 at 12:16):
oh...
Kenny Lau (Aug 10 2025 at 12:17):
well, it should then follow from tanh(x) being bounded and its derivatives vanishing
Afiq Hatta (Aug 10 2025 at 12:17):
yeah - actually thats the best way - but trying to see if there's already a ready made proof here on that result
Afiq Hatta (Aug 10 2025 at 14:19):
Just breaking this down - need to prove the lemma that tanh (x) has bounded derivatives
Afiq Hatta (Aug 10 2025 at 14:23):
can you guys tell im an absolute noob.. hahaha
Joseph Tooby-Smith (Aug 10 2025 at 17:09):
Sorry, jumping into this conversation half way through: Something like
might be useful here, all though I think it would need generalizing.
Kenny Lau (Aug 10 2025 at 17:10):
wow you've added a lot of lemmas, nice
Joseph Tooby-Smith (Aug 10 2025 at 18:10):
Yeah, they are all probably not as general as they could be - but I did a start :).
Afiq Hatta (Aug 10 2025 at 21:46):
keen to talk about this tomorrow!
Afiq Hatta (Aug 13 2025 at 13:48):
an excuritatingly dumb question which I've spent too much time on
I want to prove | tanh x | < 1
ok, so start with
lemma : tanh x < 1
there's an equality rewrite so that the goal transforms to
sinh x / cosh x < 1
but i can't for the life of me find the right package / technique that transforms this to
sinh x < cosh x
there's a preset theorem already in mathlib for sinh x < cosh x, so I just need to do the above
@Joseph Tooby-Smith
Kenny Lau (Aug 13 2025 at 13:48):
https://loogle.lean-lang.org/?q=_+%2F+_+<+1
Afiq Hatta (Aug 13 2025 at 13:51):
thanks kenny, sorry for being an idiot, still getting used to searching for things
Afiq Hatta (Aug 13 2025 at 13:52):
ah wait - those are for the natural numbers
Kenny Lau (Aug 13 2025 at 13:52):
well, not the first one
Kenny Lau (Aug 13 2025 at 13:53):
the 6th one should be what you need
Afiq Hatta (Aug 13 2025 at 13:58):
this is where im falling over the syntax a bit
Afiq Hatta (Aug 13 2025 at 13:58):
lemma tanh_le_one (x : β) : Real.tanh x < 1 := by
rw [Real.tanh_eq_sinh_div_cosh]
apply div_lt_one
Afiq Hatta (Aug 13 2025 at 13:59):
Expected type
xΒ :Β β
β’ β {Ξ± : Type ?u.1166} [inst : Semifield Ξ±] [inst_1 : LinearOrder Ξ±] [IsStrictOrderedRing Ξ±] {a b : Ξ±}, 0 < b β (a / b < 1 β a < b)
Messages (1)
Basic.lean:68:2
tactic 'apply' failed, could not unify the conclusion of @div_lt_one
?a / ?b < 1 β ?a < ?b
with the goal
sinh x / cosh x < 1
Note: The full type of @div_lt_one is
β {Ξ± : Type ?u.1166} [inst : Semifield Ξ±] [inst_1 : LinearOrder Ξ±] [IsStrictOrderedRing Ξ±] {a b : Ξ±},
0 < b β (a / b < 1 β a < b)
xΒ :Β β
β’ sinh x / cosh x < 1
All Messages (1)
Kenny Lau (Aug 13 2025 at 13:59):
it's not an apply, it's a rw
Afiq Hatta (Aug 13 2025 at 14:02):
got it - this creates a subgoal where now i need to prove 0 < cosh x as expected, and then sinh x < cosh x
Afiq Hatta (Aug 13 2025 at 14:02):
thanks kenny
Afiq Hatta (Aug 13 2025 at 14:03):
woohoo!!
lemma tanh_le_one (x : β) : Real.tanh x < 1 := by
rw [Real.tanh_eq_sinh_div_cosh]
rw [div_lt_one]
apply Real.sinh_lt_cosh
apply Real.cosh_pos
Kenny Lau (Aug 13 2025 at 14:03):
@Afiq Hatta rw rewrites an iff, apply is for applying P -> Q to a goal Q to get a goal P
Afiq Hatta (Aug 13 2025 at 14:03):
got it, and rw also works for equalities too right
Kenny Lau (Aug 13 2025 at 14:04):
yes
Afiq Hatta (Aug 13 2025 at 14:18):
one thing im finding hard is that i often want to apply results on the reals,
but most of the theorems that i get from loogle / searching mathlib or defined on like rings / fields / monoids (?!!)
Afiq Hatta (Aug 13 2025 at 14:18):
so i have to do the mental gymnastics to remember what's what
Kenny Lau (Aug 13 2025 at 14:20):
you can try to separate it out into a clean environment (i.e. example) and then use apply?:
import Mathlib
example (x y : β) : x / y < 1 β x < y := by
apply?
Afiq Hatta (Aug 15 2025 at 15:47):
@Joseph Tooby-Smith in the process of linting:
https://github.com/HEPLean/PhysLean/pull/694/files
Joseph Tooby-Smith (Aug 15 2025 at 16:38):
Going back to the problem of showing that
fun x => tanh (x) * Ο(x)
is Schwartz if Ο is, I think the general version of this result is docs#SchwartzMap.bilinLeftCLM with the bilinear map B : β βL[β] β βL[β] β taking x, y to x * y, and with g(x) = tanh(x). Thus to prove this result 'all' one would need to do is prove that Function.HasTemperateGrowth Real.tanh, which is essentially what you are trying to show anyway @Afiq Hatta .
Afiq Hatta (Aug 15 2025 at 16:43):
ooooh
Afiq Hatta (Aug 15 2025 at 16:44):
yeah good point - lets use that - thats perfectΒ±
Afiq Hatta (Aug 15 2025 at 16:45):
btw @Joseph Tooby-Smith linters passed on last commit
Joseph Tooby-Smith (Aug 15 2025 at 16:46):
Yeah,
Afiq Hatta said:
yeah good point - lets use that - thats perfectΒ±
Yeah - still need to show that tanh has bounded iterated derivatives for this, but it takes care of the 'SchwartzMap' side of the problem for you, and reduces it to a properties of 'tanh' problem.
Afiq Hatta (Aug 15 2025 at 16:46):
yeah exactly, we don't have to do the leg work of the closure stuff since we cn just use this. but still, need to prove that we have bounded iterated derivs
Afiq Hatta (Aug 22 2025 at 14:52):
@Joseph Tooby-Smith the mission here is to prove temperate growth, as a warm up going to commit these that i just did
/-
Copyright (c) 2025 Afiq Hatta. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Afiq Hatta
-/
import Mathlib.Analysis.Calculus.IteratedDeriv.Defs
import Mathlib.Data.Complex.Trigonometric
import PhysLean.Meta.Linters.Sorry
/-!
# Properties of Tanh
We want to prove that the reflectionless potential is a Schwartz map.
This means proving that pointwise multiplication of a Schwartz map with tanh is a Schwartz map.
This means we need to prove that all derivatives of tanh are bounded and continuous, so that
the nth derivative of a function multiplied by tanh decays faster than any polynomial.
## TODO
- Add these to mathlib eventually
- Fill in the proofs for the properties of tanh
-/
open Real
open NNReal
open Field
/-- tanh(x) is less than 1 for all x -/
lemma tanh_lt_one (x : β) : Real.tanh x < 1 := by
rw [Real.tanh_eq_sinh_div_cosh]
rw [div_lt_one]
apply Real.sinh_lt_cosh
apply Real.cosh_pos
/-- tanh(x) is greater than -1 for all x -/
lemma minus_one_lt_tanh (x : β) : -1 < Real.tanh x := by
rw [Real.tanh_eq_sinh_div_cosh]
rw [lt_div_iffβ]
rw [β sub_pos]
rw [neg_one_mul]
simp
apply Real.exp_pos
apply Real.cosh_pos
/-- The absolute value of tanh is bounded by 1 -/
lemma abs_tanh_lt_one (x: β) : |Real.tanh x| < 1 := by
rw [abs_lt]
constructor
apply minus_one_lt_tanh
apply tanh_lt_one
Joseph Tooby-Smith (Aug 22 2025 at 14:57):
Sounds good! I would maybe update the module doc-string with a comment about docs#SchwartzMap.bilinLeftCLM as well. Also, this is not necessary but it maybe good to know, you can combine rewrites e.g.
lemma minus_one_lt_tanh (x : β) : -1 < Real.tanh x := by
rw [Real.tanh_eq_sinh_div_cosh, lt_div_iffβ, β sub_pos, neg_one_mul]
simp
apply Real.exp_pos
apply Real.cosh_pos
ZhiKai Pong (Aug 22 2025 at 15:48):
Not the most experienced user here but some minor style comments:
- if you opened namespace
Real, you don't have to typeReal.xxx - The
cosh_posgoal arises as a result of using lemmas related to division bycosh, since it's an additional condition associated with the division lemma rather than part of the main proof personally I'd just inline it - I prefer using
exactto close goals which indicates more clearly where the proof ends - if the proof itself does require multiple goals use centerdot (
\.) to structure the proof for better clarity (e.g. after constructor).
for example, this is how I'd write your code:
import Mathlib
open Real
lemma tanh_lt_one (x : β) : tanh x < 1 := by
rw [tanh_eq_sinh_div_cosh, div_lt_one (cosh_pos x)]
exact sinh_lt_cosh x
lemma minus_one_lt_tanh (x : β) : -1 < tanh x := by
rw [tanh_eq_sinh_div_cosh, lt_div_iffβ (cosh_pos x), β sub_pos, neg_one_mul]
simp [exp_pos x]
lemma abs_tanh_lt_one (x : β) : |tanh x| < 1 := by
rw [abs_lt]
constructor
Β· exact minus_one_lt_tanh x
Β· exact tanh_lt_one x
Afiq Hatta (Aug 22 2025 at 15:51):
this is great @Joseph Tooby-Smith @ZhiKai Pong thank you for the tips
ZhiKai Pong (Aug 22 2025 at 15:52):
(I guess you can also do this once you're more comfortable)
lemma abs_tanh_lt_one (x : β) : |tanh x| < 1 := by
rw [abs_lt]
exact β¨minus_one_lt_tanh x, tanh_lt_one xβ©
Joseph Tooby-Smith (Aug 22 2025 at 16:20):
Aside concerning the center dots: there is this open issue which I attempted to do complete here, but one thing or another got in the way
Afiq Hatta (Aug 22 2025 at 17:19):
guys i have a mega dumb question
/-- Tanh(x) is n times continuously differentiable for all n -/
lemma contDiff_tanh {n : β} : ContDiff β n tanh := by
have hdiv : ContDiff β n (fun x => Real.sinh x / Real.cosh x) := by
apply ContDiff.div
Β· exact contDiff_sinh
Β· exact contDiff_cosh
Β· intro x
exact ne_of_gt (Real.cosh_pos x)
simpa [tanh_eq_sinh_div_cosh] using hdiv
the last line is throwing error -
type mismatch, term
hdiv
after simplification has type
ContDiff β βn fun x => sinh x / cosh x : Prop
but is expected to have type
ContDiff β (βn) tanh : Prop
what is the syntax to use the tanh = sinh / coosh to finally prove this thing?
Afiq Hatta (Aug 22 2025 at 17:20):
rewriting the goal with rw [ tanh_eq_sinh_div_cosh] doesn't work
ZhiKai Pong (Aug 22 2025 at 17:35):
here's a possible solution (there might be an easier way) (also I'm surprised this isn't in Mathlib)
import Mathlib
open Real
/-- Tanh(x) is n times continuously differentiable for all n -/
lemma contDiff_tanh {n : β} : ContDiff β n tanh := by
have hdiv : ContDiff β n (fun x => sinh x / cosh x) := by
apply ContDiff.div
Β· exact contDiff_sinh
Β· exact contDiff_cosh
Β· intro x
exact ne_of_gt (cosh_pos x)
conv =>
enter [3, x]
rw [tanh_eq_sinh_div_cosh]
exact hdiv
ZhiKai Pong (Aug 22 2025 at 17:37):
there are two layers of issue here:
rwcan't see through what's insideContDifftanh_eq_sinh_div_coshhas to be of the formtanh x = sinh x / cosh x, so you have to give it anx. Not sure if you're familiar withext, theenteris just doing that in a similar fashion
Afiq Hatta (Aug 22 2025 at 17:40):
ah - yeah i wanted to figure out how to do the replacement of tanh within ContDiff
Afiq Hatta (Aug 22 2025 at 17:46):
thank you for this
ZhiKai Pong (Aug 22 2025 at 17:48):
No worries!
Afiq Hatta (Aug 22 2025 at 17:49):
btw i couldn't find this in mathlib - do you agree it's not there? still trying to build my searching skills
ZhiKai Pong (Aug 22 2025 at 17:54):
(sorry first time trying to do this in zulip)
ZhiKai Pong (Aug 22 2025 at 17:55):
@loogle tanh
loogle (Aug 22 2025 at 17:55):
:exclamation: unknown identifier 'tanh'
Did you mean "tanh", Float.tanh, or something else?
ZhiKai Pong (Aug 22 2025 at 17:56):
@loogle Real.tanh
loogle (Aug 22 2025 at 17:56):
:search: Real.tanh, Complex.ofReal_tanh, and 7 more
ZhiKai Pong (Aug 22 2025 at 17:57):
@loogle Real.sinh
loogle (Aug 22 2025 at 17:57):
:search: Real.sinh, Real.sinh_lt_cosh, and 117 more
ZhiKai Pong (Aug 22 2025 at 17:57):
It's quite clear that a lot is missing for tanh :)
ZhiKai Pong (Aug 22 2025 at 17:57):
(this is https://loogle.lean-lang.org/)
Afiq Hatta (Aug 22 2025 at 17:57):
yeah - reflectionless potential sidequests to the rescue!! XD
Afiq Hatta (Aug 22 2025 at 19:51):
@Joseph Tooby-Smith i submitted a pull request but no rush - its fridayyy night!!!
Joseph Tooby-Smith (Aug 22 2025 at 19:54):
Ha - no worries, was literally doing it as I got this message :)
Afiq Hatta (Aug 23 2025 at 14:33):
@Joseph Tooby-Smith to prove the derivative of tanh x - will using the identity below make this a bit easier, then using the chain rule on this - or will there be shenanigans with Real / Complex
theorem tanh_mul_I : tanh (x * I) = tan x * I := by
rw [tanh_eq_sinh_div_cosh, cosh_mul_I, sinh_mul_I, mul_div_right_comm, tan]
Joseph Tooby-Smith (Aug 23 2025 at 16:00):
This might work, it really depends on how good the API is around real to complex numbers - if I recall it is quite good.
Afiq Hatta (Aug 26 2025 at 11:48):
@Joseph Tooby-Smith really DUMB q i cant seem to rewrite the goal here so that i can use my h result
/-- The derivative of tanh(x) is 1 - tanh(x)^2 -/
lemma deriv_tanh (x: β) : deriv Real.tanh = fun x => 1 - Real.tanh x ^ 2 := by
have h: deriv (sinh / cosh) x = 1 - Real.tanh x ^ 2 := by
rw [deriv_div, Real.deriv_sinh, Real.deriv_cosh]
field_simp
rw [sq, sq, tanh_eq_sinh_div_cosh, mul_sub_right_distrib]
field_simp
Β· apply Real.differentiable_sinh
Β· apply Real.differentiable_cosh
Β· exact ne_of_gt (Real.cosh_pos x)
tanh_eq_sinh_div_cosh is the result tanh x = sinh x / cosh x
using funext x i think rewrites that goal as (deriv Real.tanh) x , so the pesky symbols aren't in the right place
Afiq Hatta (Aug 26 2025 at 11:49):
i have this
unsolved goals
xΒ :Β β
hΒ :Β deriv (sinh / cosh) x = 1 - tanh x ^ 2
β’ deriv tanh = fun x => 1 - tanh x ^ 2
Afiq Hatta (Aug 26 2025 at 11:50):
i could make a functional version of
tanh_eq_sinh_div_cosh such that tanh = sinh / cosh, and then change the form of h to make it "functional" but i m not sure how to do that
Afiq Hatta (Aug 26 2025 at 11:52):
(deleted)
Joseph Tooby-Smith (Aug 26 2025 at 11:55):
try funext x :)
Afiq Hatta (Aug 26 2025 at 11:56):
OH WAIT I GOT IT i think
Afiq Hatta (Aug 26 2025 at 11:56):
i think i answered my own question by asking it hah
Afiq Hatta (Aug 26 2025 at 11:59):
boom
/-- The derivative of tanh(x) is 1 - tanh(x)^2 -/
lemma deriv_tanh : deriv Real.tanh = fun x => 1 - Real.tanh x ^ 2 := by
have h: deriv (sinh / cosh) = fun x => 1 - Real.tanh x ^ 2 := by
funext x
rw [deriv_div, Real.deriv_sinh, Real.deriv_cosh]
field_simp
rw [sq, sq, tanh_eq_sinh_div_cosh, mul_sub_right_distrib]
field_simp
Β· apply Real.differentiable_sinh
Β· apply Real.differentiable_cosh
Β· exact ne_of_gt (Real.cosh_pos x)
have h': Real.tanh = (sinh / cosh) := by
funext x
rw [Pi.div_apply, tanh_eq_sinh_div_cosh]
nth_rewrite 1 [h']
apply h
Afiq Hatta (Aug 26 2025 at 11:59):
one big leap for tanh
Afiq Hatta (Aug 26 2025 at 11:59):
okay will commit this
Joseph Tooby-Smith (Aug 26 2025 at 11:59):
Nice, congrats! :grinning:
Joseph Tooby-Smith (Aug 26 2025 at 12:06):
So I don't have an explanation for this, other then 'field_simp' is an awesome tactic, but your proof of h can be golfed to:
import Mathlib
open Real
/-- The derivative of tanh(x) is 1 - tanh(x)^2 -/
lemma deriv_tanh : deriv Real.tanh = fun x => 1 - Real.tanh x ^ 2 := by
have h: deriv (sinh / cosh) = fun x => 1 - Real.tanh x ^ 2 := by
funext x
field_simp [deriv_div, Real.deriv_sinh, Real.deriv_cosh, sq,
tanh_eq_sinh_div_cosh, mul_sub_right_distrib]
have h': Real.tanh = (sinh / cosh) := by
funext x
rw [Pi.div_apply, tanh_eq_sinh_div_cosh]
nth_rewrite 1 [h']
apply h
(I think this is something one would only find given an already complete proof)
Afiq Hatta (Aug 26 2025 at 13:27):
awesome.
i also have another dumb question: if, in an inductive proof, we use the inductive hypothesis, how do we 'obtain' that object from it and use it.
example:
/-- The nth derivative of Tanh(x) is a polynomial of Tanh(x) -/
lemma iteratedDeriv_tanh_is_polynomial_of_tanh (n : β) (x : β) : β P : Polynomial β, β x,
iteratedDeriv n Real.tanh x = P.eval (Real.tanh x) := by
induction n
rw [iteratedDeriv_zero]
use Polynomial.X
simp
rw [iteratedDeriv_succ]
im trying to 'use' the polynomial in the induction hypothesis
case succ
xΒ :Β β
nβΒ :Β β
aβΒ :Β β P, β (x : β), iteratedDeriv nβ tanh x = Polynomial.eval (tanh x) P
β’ β P, β (x : β), deriv (iteratedDeriv nβ tanh) x = Polynomial.eval (tanh x) P
Afiq Hatta (Aug 26 2025 at 13:28):
so here we have in aβ that there is some polynomial such that nth iterated deriv is a polynomial of tan, and i want to sub that into the goal
Joseph Tooby-Smith (Aug 26 2025 at 13:41):
I think the tactic you want is obtain. I would set this up as follows:
import Mathlib
open Real
/-- The nth derivative of Tanh(x) is a polynomial of Tanh(x) -/
lemma iteratedDeriv_tanh_is_polynomial_of_tanh (n : β) (x : β) : β P : Polynomial β, β x,
iteratedDeriv n Real.tanh x = P.eval (Real.tanh x) := by
induction n with
| zero =>
rw [iteratedDeriv_zero]
use Polynomial.X
simp
| succ n ih =>
obtain β¨P, h'β© := ih
rw [iteratedDeriv_succ]
sorry
Afiq Hatta (Aug 26 2025 at 13:41):
dumb question so where does ih come from here ?
Afiq Hatta (Aug 26 2025 at 13:41):
ah no worries, got it
Joseph Tooby-Smith (Aug 26 2025 at 13:43):
More generally you can get rid of the β's with the expose_names tactic.
Afiq Hatta (Aug 26 2025 at 13:44):
got it, thanks joe
Afiq Hatta (Aug 26 2025 at 13:45):
okok so i have to modify P then use it
Joseph Tooby-Smith (Aug 26 2025 at 13:52):
Yeah, the P in your goal is not going to be the same one you obtain from the induction hypothesis.
Namely I think the one in your goal should be (1 - X ^ 2) * Polynomial.derivative P or something along those lines
Afiq Hatta (Aug 26 2025 at 13:53):
yeah
Afiq Hatta (Aug 26 2025 at 13:54):
need to rewrite deriv (iteratedDeriv n tanh) x as deriv (Polynomial.eval (tanh x) P ), then apply chain rule, then use modified ploynomail
Joseph Tooby-Smith (Aug 26 2025 at 13:55):
Yep, this seems right to me.
Afiq Hatta (Aug 26 2025 at 14:37):
hm - im pretty sure i've got this rewrite correct, but still getting a fail
β’ β P_1, β (x : β), deriv ((fun t => Polynomial.eval t P) β tanh) x = Polynomial.eval (tanh x) P_1
Tanh.lean:92:8
tactic 'rewrite' failed, did not find instance of the pattern in the target expression
deriv (?hβ β ?h) ?x
*
Afiq Hatta (Aug 26 2025 at 14:38):
applying the derivative composition theorem here
Joseph Tooby-Smith (Aug 26 2025 at 14:38):
Could you paste a code snippet with the failing rewrite?
Afiq Hatta (Aug 26 2025 at 14:38):
lemma iteratedDeriv_tanh_is_polynomial_of_tanh (n : β) (x : β) : β P : Polynomial β, β x,
iteratedDeriv n Real.tanh x = P.eval (Real.tanh x) := by
induction n with
| zero =>
rw [iteratedDeriv_zero]
use Polynomial.X
simp
| succ n ih =>
obtain β¨P, h'β© := ih
rw [iteratedDeriv_succ]
have h'': iteratedDeriv n tanh = (fun x => Polynomial.eval (tanh x) P) := by
funext x
apply h'
have h_comp : (fun x => Polynomial.eval (tanh x) P) = (fun t => P.eval t) β tanh := by
funext x
simp [Function.comp_apply]
rw [h'']
rw [h_comp]
rw [deriv_comp]
Afiq Hatta (Aug 26 2025 at 14:38):
its that last deriv_comp that fails
Afiq Hatta (Aug 26 2025 at 14:41):
is this a teachable moment - the symbols match up, but the match isn't working, is there something else that has to match, like the type on t?
ZhiKai Pong (Aug 26 2025 at 14:50):
get rid of the quantifiers first, i.e. use P and intro x(I'm just guessing from the infoview)
Kevin Buzzard (Aug 26 2025 at 15:03):
rw sometimes doesn't work under binders. You could try simp_rw or simp only instead.
Afiq Hatta (Aug 26 2025 at 18:23):
thank you both @ZhiKai Pong and @Kevin Buzzard and also @Joseph Tooby-Smith
this ended up working. now on the way to prove that tanh has temperate growth and therefore is a schwartz operator!
lemma iteratedDeriv_tanh_is_polynomial_of_tanh (n : β) : β P : Polynomial β, β x,
iteratedDeriv n Real.tanh x = P.eval (Real.tanh x) := by
induction n with
| zero =>
rw [iteratedDeriv_zero]
use Polynomial.X
simp
| succ n ih =>
obtain β¨P, h'β© := ih
rw [iteratedDeriv_succ]
have h'': iteratedDeriv n tanh = (fun x => Polynomial.eval (tanh x) P) := by
funext x
apply h'
have h_comp : (fun x => Polynomial.eval (tanh x) P) = (fun t => P.eval t) β tanh := by
funext x
simp [Function.comp_apply]
rw [h'', h_comp]
use Polynomial.derivative P * (1 - Polynomial.X^2)
intro x
rw [deriv_comp, Polynomial.deriv, deriv_tanh]
simp
case h.hh =>
have h': Real.tanh = (sinh / cosh) := by
funext x
rw [Pi.div_apply, tanh_eq_sinh_div_cosh]
rw [h']
apply DifferentiableAt.div
Β· apply Real.differentiable_sinh
Β· apply Real.differentiable_cosh
Β· exact ne_of_gt (Real.cosh_pos x)
case h.hhβ =>
apply Polynomial.differentiableAt
Daniel Morrison (Aug 26 2025 at 20:23):
Joseph Tooby-Smith said:
import Mathlib open Real /-- The nth derivative of Tanh(x) is a polynomial of Tanh(x) -/ lemma iteratedDeriv_tanh_is_polynomial_of_tanh (n : β) (x : β) : β P : Polynomial β, β x, iteratedDeriv n Real.tanh x = P.eval (Real.tanh x) := by induction n with | zero => rw [iteratedDeriv_zero] use Polynomial.X simp | succ n ih => obtain β¨P, h'β© := ih rw [iteratedDeriv_succ] sorry
I will add that it is useful to use induction' rather than induction. It does essentially the same thing but is a bit more user friendly. You can name the variable in the induction line by saying for example induction' n with n ih in this example. It also separates the goals more nicely so you can rewrite this as
induction' n with n ih
. rw [iteratedDeriv_zero]
use Polynomial.X
simp
. obtain β¨P, h'β© := ih
rw [iteratedDeriv_succ]
sorry
which I find a little bit nicer to read. (I haven't checked this code but I think it should be right)
Matteo Cipollina (Aug 26 2025 at 20:50):
Joseph Tooby-Smith ha scritto:
More generally you can get rid of the
β's with theexpose_namestactic.
While a great heuristic, eventually it would be preferable safer to get rid of expose_names as well
Afiq Hatta (Aug 26 2025 at 20:53):
thanks for the tips team :) will clean the code up tomorrow morning with the alternative induction syntax
Joseph Tooby-Smith (Aug 27 2025 at 04:57):
Matteo Cipollina said:
Joseph Tooby-Smith ha scritto:
More generally you can get rid of the
β's with theexpose_namestactic.While a great heuristic, eventually it would be
preferablesafer to get rid ofexpose_namesas well
It is better to use e.g. rename?
Matteo Cipollina (Aug 27 2025 at 06:28):
Joseph Tooby-Smith ha scritto:
Matteo Cipollina said:
Joseph Tooby-Smith ha scritto:
More generally you can get rid of the
β's with theexpose_namestactic.While a great heuristic, eventually it would be
preferablesafer to get rid ofexpose_namesas wellIt is better to use e.g.
rename?
Yes, or combination of rw-exact often works for me
Afiq Hatta (Aug 28 2025 at 10:07):
hey @Joseph Tooby-Smith - im falling over a bit on how to formalise 'this function has temperate growth'
Afiq Hatta (Aug 28 2025 at 10:11):
not sure which exact property to use - brain is not braining
Afiq Hatta (Aug 28 2025 at 10:12):
if you have an example or hint i can take it from there
Joseph Tooby-Smith (Aug 28 2025 at 10:12):
I think the next step would be to show that for any polynomial P, Polynomial.eval (tanh x) P is bounded. I'm not actually sure the best way of doing this though.
Afiq Hatta (Aug 28 2025 at 10:12):
cool, i can do that first
Afiq Hatta (Aug 28 2025 at 10:13):
presumably there is some property in mathlib that represents 'bounded for all x in \R'
Afiq Hatta (Aug 28 2025 at 10:23):
ah actually i reckon can just do this
lemma polynomials_tanh_bounded : β P : Polynomial β, β C : β, β x : β, |P.eval (Real.tanh x)| < C :=
sorry
Joseph Tooby-Smith (Aug 28 2025 at 10:23):
I think if there is it would be then the temperate growth proposition would us it (and I don't think it does). But I think the thing you want is:
import Mathlib
open Real Polynomial
example (P : Polynomial β) : β C, β x, P.eval (tanh x) β€ C := by sorry
Afiq Hatta (Aug 28 2025 at 10:23):
omg hahah
Afiq Hatta (Aug 28 2025 at 10:24):
we literally wrote that at the same time
Joseph Tooby-Smith (Aug 28 2025 at 10:24):
haha yep, either of these would work, actually I think yours is better because you have abs :).
Joseph Tooby-Smith (Aug 28 2025 at 10:25):
Btw when putting code snippets into Zulip it helps to put the necessary preamble e.g.
import Mathlib
open Real Polynomial
...
That way people can open the code snippet in https://live.lean-lang.org by pressing the pop-up in the top right corner of the snippet, and everything will compile nicely :).
Afiq Hatta (Aug 28 2025 at 10:26):
ah - didn't realise you could do that - awesome
Afiq Hatta (Aug 28 2025 at 11:49):
this all works - i proved that the iteratived derivative of tanh is bounded
import PhysLean.Meta.Linters.Sorry
import Mathlib.Analysis.SpecialFunctions.Trigonometric.Deriv
import Mathlib.Data.Complex.Trigonometric
import Mathlib.Analysis.Calculus.Deriv.Polynomial
import Mathlib.Topology.Algebra.Polynomial
/-!
# Properties of Tanh
We want to prove that the reflectionless potential is a Schwartz map.
This means proving that pointwise multiplication of a Schwartz map with tanh is a Schwartz map.
This means we need to prove that all derivatives of tanh are bounded and continuous, so that
the nth derivative of a function multiplied by tanh decays faster than any polynomial.
## TODO
- Add these to mathlib eventually
- Fill in the proofs for the properties of tanh
-/
open Real
open NNReal
open Field
/-- tanh(x) is less than 1 for all x -/
lemma tanh_lt_one (x : β) : tanh x < 1 := by
rw [tanh_eq_sinh_div_cosh, div_lt_one (cosh_pos x)]
exact sinh_lt_cosh x
/-- tanh(x) is greater than -1 for all x -/
lemma minus_one_lt_tanh (x : β) : -1 < tanh x := by
rw [tanh_eq_sinh_div_cosh, lt_div_iffβ (cosh_pos x), β sub_pos, neg_one_mul]
simp [exp_pos x]
/-- The absolute value of tanh is bounded by 1 -/
lemma abs_tanh_lt_one (x : β) : |tanh x| < 1 := by
rw [abs_lt]
constructor
Β· exact minus_one_lt_tanh x
Β· exact tanh_lt_one x
/-- The derivative of tanh(x) is 1 - tanh(x)^2 -/
lemma deriv_tanh : deriv Real.tanh = fun x => 1 - Real.tanh x ^ 2 := by
have h: deriv (sinh / cosh) = fun x => 1 - Real.tanh x ^ 2 := by
funext x
rw [deriv_div, Real.deriv_sinh, Real.deriv_cosh]
field_simp
rw [sq, sq, tanh_eq_sinh_div_cosh, mul_sub_right_distrib]
field_simp
Β· apply Real.differentiable_sinh
Β· apply Real.differentiable_cosh
Β· exact ne_of_gt (Real.cosh_pos x)
have h': Real.tanh = (sinh / cosh) := by
funext x
rw [Pi.div_apply, tanh_eq_sinh_div_cosh]
nth_rewrite 1 [h']
apply h
/-- Tanh(x) is n times continuously differentiable for all n -/
lemma contDiff_tanh {n : β} : ContDiff β n tanh := by
have hdiv : ContDiff β n (fun x => Real.sinh x / Real.cosh x) := by
apply ContDiff.div
Β· exact contDiff_sinh
Β· exact contDiff_cosh
Β· intro x
exact ne_of_gt (Real.cosh_pos x)
conv =>
enter [3, x]
rw [tanh_eq_sinh_div_cosh]
exact hdiv
/-- The nth derivative of Tanh(x) is a polynomial of Tanh(x) -/
lemma iteratedDeriv_tanh_is_polynomial_of_tanh (n : β) : β P : Polynomial β, β x,
iteratedDeriv n Real.tanh x = P.eval (Real.tanh x) := by
induction n with
| zero =>
rw [iteratedDeriv_zero]
use Polynomial.X
simp
| succ n ih =>
obtain β¨P, h'β© := ih
rw [iteratedDeriv_succ]
have h'': iteratedDeriv n tanh = (fun x => Polynomial.eval (tanh x) P) := by
funext x
apply h'
have h_comp : (fun x => Polynomial.eval (tanh x) P) = (fun t => P.eval t) β tanh := by
funext x
simp [Function.comp_apply]
rw [h'', h_comp]
use Polynomial.derivative P * (1 - Polynomial.X^2)
intro x
rw [deriv_comp, Polynomial.deriv, deriv_tanh]
simp
case h.hh =>
have h': Real.tanh = (sinh / cosh) := by
funext x
rw [Pi.div_apply, tanh_eq_sinh_div_cosh]
rw [h']
apply DifferentiableAt.div
Β· apply Real.differentiable_sinh
Β· apply Real.differentiable_cosh
Β· exact ne_of_gt (Real.cosh_pos x)
case h.hhβ =>
apply Polynomial.differentiableAt
-- For a polynomial P, show it's bounded on any bounded interval
lemma polynomial_bounded_on_interval (P : Polynomial β) (a b : β):
β M : β, β x : β, x β Set.Icc a b β |P.eval x| β€ M := by
-- Polynomials are continuous
have hcont : Continuous (fun x => P.eval x) := P.continuous -- Closed bounded intervals are compact
have hcompact : IsCompact (Set.Icc a b) := isCompact_Icc
-- Continuous functions on compact sets are bounded
obtain β¨M, hMβ© := hcompact.exists_bound_of_continuousOn hcont.continuousOn
use M
exact hM
-- For a polynomial P, show that P (tanh x) is bounded on the real line
theorem polynomial_tanh_bounded (P : Polynomial β) :
β C : β, β x : β, |P.eval (Real.tanh x)| β€ C := by
have h_range : β x : β, Real.tanh x β Set.Icc (-1) 1 := by
intro x
constructor
Β· exact le_of_lt (minus_one_lt_tanh x)
Β· exact le_of_lt (tanh_lt_one x)
-- Apply polynomial boundedness on [-1, 1]
obtain β¨M, hMβ© := polynomial_bounded_on_interval P (-1) 1
use M
intro x
exact hM (Real.tanh x) (h_range x)
-- The nth derivative of tanh is bounded on the real line
theorem iteratedDeriv_tanh_bounded (n : β) :
β C : β, β x : β, |iteratedDeriv n Real.tanh x| β€ C := by
obtain β¨P, hPβ© := iteratedDeriv_tanh_is_polynomial_of_tanh n
obtain β¨C, hCβ© := polynomial_tanh_bounded P
use C
intro x
rw [hP]
exact hC x
Joseph Tooby-Smith (Aug 28 2025 at 11:54):
Nice! This looks great! Proving that tanh has temperate growth should now follow fairly trivially right?
Afiq Hatta (Aug 28 2025 at 11:54):
dumb question - where is the 'temperate growth' property?
Joseph Tooby-Smith (Aug 28 2025 at 11:56):
(deleted)
Joseph Tooby-Smith (Aug 28 2025 at 11:56):
@loogle Function.HasTemperateGrowth
loogle (Aug 28 2025 at 11:56):
:search: Function.HasTemperateGrowth, Function.HasTemperateGrowth.const, and 9 more
Joseph Tooby-Smith (Aug 28 2025 at 11:57):
So "Mathlib.Analysis.Distribution.SchwartzSpace"
Afiq Hatta (Aug 28 2025 at 11:57):
btw is anyone else getting 404s accessing https://leanprover-community.github.io/?
Afiq Hatta (Aug 28 2025 at 11:57):
got it - will prove that and then commit this soup
Joseph Tooby-Smith (Aug 28 2025 at 11:58):
Afiq Hatta said:
btw is anyone else getting 404s accessing https://leanprover-community.github.io/?
Works for me.
Afiq Hatta (Aug 28 2025 at 13:09):
really dumb question - i'm struggling with going from 'for all n' to 'infinitely differentiable' here - why is there a token error on the \infty part of this lemma?
import PhysLean.Meta.Linters.Sorry
import Mathlib.Analysis.SpecialFunctions.Trigonometric.Deriv
import Mathlib.Data.Complex.Trigonometric
import Mathlib.Analysis.Calculus.Deriv.Polynomial
import Mathlib.Topology.Algebra.Polynomial
import Mathlib.Analysis.Distribution.SchwartzSpace
open Real
open NNReal
open Field
-- Alternative approach for the smoothness part:
/-- tanh is infinitely differentiable -/
lemma contDiff_top_tanh : ContDiff β β Real.tanh x := by
-- Show that tanh is ContDiff for all finite orders, which implies ContDiff β€
-- apply ContDiff.of_le
-- Β· exact contDiff_tanh
-- Β· exact le_top
sorry
Afiq Hatta (Aug 28 2025 at 13:10):
A bit confused on the type of infty here it expects. the code says n can also be N\infty but that doesn't work either
Afiq Hatta (Aug 28 2025 at 13:16):
The goal i'm aiming for here is
ContDiff β (ββ€) tanh
ZhiKai Pong (Aug 28 2025 at 13:19):
from a previous conversation:
Aaron Liu: Read carefully: docs#ContDiff takes a WithTop ENat, which has two tops. The higher top ("omega") is for analytic functions, and the lower top ("infinity") is for smooth (infinitely differentiable) functions.
Aaron Liu: If you open scoped ContDiff it'll print these differently.
Afiq Hatta (Aug 28 2025 at 13:21):
works! thankas @ZhiKai Pong
Afiq Hatta (Sep 03 2025 at 10:29):
hey @Joseph Tooby-Smith I was wondering if there was a theorem on compositions of two temperate growth functions having temperate growth
Afiq Hatta (Sep 03 2025 at 10:29):
i couldn't find it - and needed it to easily show that tanh ( k x ) is temperate for all k real
Afiq Hatta (Sep 03 2025 at 10:34):
if not, i can sketch up a proof?
Joseph Tooby-Smith (Sep 03 2025 at 10:37):
I don't think so, but it might just be easier to show that tanh ( k x ) has temperate growth given tanh x has temperate growth.
Afiq Hatta (Sep 03 2025 at 10:38):
yeah
Afiq Hatta (Sep 03 2025 at 10:39):
i actually don't know if the composition of two temperate growth functions has temperate growth anyway.
Joseph Tooby-Smith (Sep 03 2025 at 10:42):
I think it probably is true - because the iterated derivative of the composition becomes the sum of iterated derivatives of each part via the chain rule, which should be bounded. Proving it formally is a different matter though.
Joseph Tooby-Smith (Sep 03 2025 at 10:48):
It may also be possible/quickest to modify your proofs for tanh x and turn them into proofs of tanh (k * x)
Afiq Hatta (Sep 08 2025 at 15:02):
Hey guys, I have a dumb question. To show that tanh is a Schwartz map: after I apply tanh, there has to be a trivial embedding of Real.tanh into the complex numbers. I then need to show that this composition has temperate growth. Is there any easier way of doing this besides proving that the composition of temperate growth maps is also temperate, or redoing the whole proof of temperateGrowth of tanh in \C ?
-- Scaled tanh embedded into the complex numbers has temperate growth
theorem scaled_tanh_complex_hasTemperateGrowth (ΞΊ : β) :
Function.HasTemperateGrowth (fun x => (Real.tanh (ΞΊ * x) : β)) := by
sorry
/-- Define tanh(ΞΊ X) multiplication pointwise as a Schwartz map -/
noncomputable def tanhOperatorSchwartz (Q : ReflectionlessPotential) :
π’(β, β) βL[β] π’(β, β) := by
-- We need to handle the Real β Complex coercion
let scaled_tanh_real : β β β := fun x => Real.tanh (Q.ΞΊ * x)
let scaled_tanh_complex : β β β := fun x => (Real.tanh (Q.ΞΊ * x) : β)
have h2 : Function.HasTemperateGrowth scaled_tanh_complex
:= scaled_tanh_complex_hasTemperateGrowth Q.ΞΊ
exact bilinLeftCLM (ContinuousLinearMap.mul β β) h2
ZhiKai Pong (Sep 08 2025 at 15:08):
The way you phrase this makes me think you should probably have a separate lemma that proves any trivial embedding of real Schwartz maps into the complex also has temperate growth and just apply that, but I'm not sure how feasible as I'm not that familiar with the Schwartz map API at the moment
Afiq Hatta (Sep 08 2025 at 15:09):
yeah that's what i was thinking as well. I am still new to lean so was wondering if there was any quick keyword that does this for me, but I guess not
Afiq Hatta (Sep 08 2025 at 19:44):
@Joseph Tooby-Smith i wrote a pull request for definitions for the creation and operation operators, leaving a sorry statement for the proof of the embedding thing that I need
Joseph Tooby-Smith (Sep 09 2025 at 08:12):
I think this is what you want:
Code
Found it by loogling iteratedFDeriv, "comp" and spotting LinearIsometry.norm_iteratedFDeriv_comp_left.
(Edits: Golf)
Afiq Hatta (Sep 09 2025 at 08:37):
Thanks! I'll take some go through this example because I actually don't know a lot of these keywords. Btw - I see that you're a fan of using 'refine' - what kinds of problems lend well to using that keyword?
Afiq Hatta (Sep 09 2025 at 08:39):
like why use refine And.intro, vs something like constructor?
Joseph Tooby-Smith (Sep 09 2025 at 08:46):
refine is basically exact but you can have holes in it which are the ?_. Your goal then becomes what is needed to fill in the ?_. In some interactive theorem provers like Agda this sort of manipulation is basically all that is used. I like to view refine, exact and apply as sitting in the same collection of tactics.
I personally tend not to use constructor that often because for some reason I only recently learnt about it - and I have a habit of using refine And.intro ?_ ?_ or apply And.intro etc.
Afiq Hatta (Sep 09 2025 at 08:47):
got it - makes sense
Afiq Hatta (Sep 09 2025 at 09:01):
Where do we think is an appropriate place to put the embedding theorem that you wrote?
Joseph Tooby-Smith (Sep 09 2025 at 09:02):
I would probably just put it as a private lemma just before you need it for now.
Joseph Tooby-Smith (Sep 09 2025 at 09:03):
(FYI - I just cleaned it up some more)
Joseph Tooby-Smith (Sep 09 2025 at 09:07):
I should also say - for reference that my proof above is after golfing to make it shorter and nice - I started with something a lot longer and messier.
Afiq Hatta (Sep 09 2025 at 09:09):
got it. that's good to know, because when i read some solutions i'm like 'how...!!'. the way I've been trying to get at solutions is by doing
constructor
apply
apply
apply
till the cows come home, just trying to match goals with theorems in mathlib and then only golfing after.
Joseph Tooby-Smith (Sep 09 2025 at 09:11):
Yeah I think this is common and this is what I do too. Once you have a working proof it is relatively easy to make it shorter - that said there are lots of proofs within PhysLean that have never been golfed :).
Afiq Hatta (Sep 09 2025 at 09:20):
yeah. ok my mission for today is to add this and also maybe just write some words on my blog about the general strategy of just apply apply apply then golfing later.
Afiq Hatta (Sep 09 2025 at 09:54):
@Joseph Tooby-Smith here's a really dumb question - I often get stuck on rewrites not matching the target but it does take a lot of time to figure out what's going on. Is there anything that I can do to make the trouble shooting a bit easier? For example, I'm trying to do the proof on my own and I don't know why this final rewrite is failing?
lemma complex_embedding_of_temperate_growth(f : β β β) (h : Function.HasTemperateGrowth f) :
Function.HasTemperateGrowth (fun x => (f x : β)) := by
constructor
apply ContDiff.fun_comp
apply ContinuousLinearMap.contDiff Complex.ofRealCLM
obtain β¨h1, h2β© := h
apply h1
obtain β¨h1, h2β© := h
intro n
use 0
use 0
intro x
have h : (fun x => ((f x) : β)) = (Complex.ofRealCLM β f) := by
sorry
rw [h]
apply LinearIsometry.norm_iteratedFDeriv_comp_left
Afiq Hatta (Sep 09 2025 at 10:01):
i'm just as curious about the trouble shooting here (ie how to check if I got anything wrong with types etc, and obvious ways to spot errors) as well as what went wrong in this specific example
Joseph Tooby-Smith (Sep 09 2025 at 10:26):
You mean the finial apply? The last rw looks like it's working to me.
Afiq Hatta (Sep 09 2025 at 10:28):
sorry - the final apply!
Afiq Hatta (Sep 09 2025 at 10:28):
i can't seem to get it to work
Joseph Tooby-Smith (Sep 09 2025 at 10:30):
Two reasons:
- You need
RCLike.ofRealLInotComplex.ofRealCLMinh. The former is a linear isometry whilst the latter is a continuous linear map. As functions they are both equal, but have different types. - To use
applyyour goal has to be the same as the theorem given, in this case it is not. However, once you have made the change1here, thenrw [LinearIsometry.norm_iteratedFDeriv_comp_left]should work.
Afiq Hatta (Sep 09 2025 at 10:36):
ah - so does the break come from the actual type being wrong? because usually, what happens is that i apply the theorem, and then a subgoal is created in which i prove that something satisfies that. but i guess that only applies to hypotheses
Joseph Tooby-Smith (Sep 09 2025 at 10:40):
Here is a short description of what apply does:
Let us say you have a proof h : A β B β C and your goal is equal to C, then apply h will great subgoals for A and B. But if your goal is not currently C then you can't use apply h.
I don't really use e.g. apply _ at _ so don't know how that works exactly.
Afiq Hatta (Sep 09 2025 at 10:41):
got it - that's clear - thanks Joe
ZhiKai Pong (Sep 09 2025 at 11:11):
@Joseph Tooby-Smith may I ask how do you inspect this code? since this depends on an open PR, is there a way to directly play around with it or do you just copy the relevant lemmas to your local PhysLean?
Joseph Tooby-Smith (Sep 09 2025 at 12:38):
For this specific example the lemma I ended up proving didn't actually need anything from the PR, so I just used https://live.lean-lang.org.
But more generally, if there is something I want to look at from a given PR or play around with in more detail, I will just check out the corresponding PR. Which on github desktop is done via:
Screenshot 2025-09-09 at 13.38.18.png
Afiq Hatta (Sep 09 2025 at 15:10):
@Joseph Tooby-Smith
my own attempt (learning)
lemma complex_embedding_of_temperate_growth(f : β β β) (h : Function.HasTemperateGrowth f) :
Function.HasTemperateGrowth (fun x => (f x : β)) := by
constructor
apply ContDiff.fun_comp
apply ContinuousLinearMap.contDiff Complex.ofRealCLM
obtain β¨h1, h2β© := h
apply h1
obtain β¨h1, h2β© := h
intro n
obtain β¨k, C, jβ© := h2 n
use k
use C
intro x
have h : (fun x => (Complex.ofReal β f) x) = (RCLike.ofRealLI (K := β) β f) := by
funext x
simp
have h'' : (fun x => (f x : β)) = (fun x => (Complex.ofReal β f) x) := rfl
rw [h'']
rw [h]
rw [LinearIsometry.norm_iteratedFDeriv_comp_left (g := RCLike.ofRealLI (K := β)) (hf := h1.contDiffAt)]
apply j
apply ENat.natCast_le_of_coe_top_le_withTop
simp only [le_refl]
Joseph Tooby-Smith (Sep 09 2025 at 15:12):
Awesome! I would now play the game to see how much you can golf this, maybe using tactics you are less familiar with.
Afiq Hatta (Sep 09 2025 at 15:14):
yeah. i've starting writing some notes on useful go to tactics for beginners which i'll publish tonight
Joseph Tooby-Smith (Sep 09 2025 at 15:15):
Nice! I would be interested to see at some point what are the most common tactics used in e.g. PhysLean compared to Mathlib etc.
I would advocate for conv_lhs, conv_rhs to be part of that list - once I discovered them they were a life-changer.
ZhiKai Pong (Sep 09 2025 at 15:34):
@Afiq Hatta
I did the same earlier but waited for you to finish, just some minor comments:
import Mathlib
lemma complex_embedding_of_temperate_growth(f : β β β) (h : Function.HasTemperateGrowth f) :
Function.HasTemperateGrowth (fun x => (f x : β)) := by
-- once you structure the code you'll see that the reason you had two of the same obtains was because they were in different branches so you can just put it before constructor
-- in general always use dot notation to structure the proof whenever you use constructor and create multiple goals
obtain β¨h1, h2β© := h
constructor
Β· apply ContDiff.fun_comp
apply ContinuousLinearMap.contDiff Complex.ofRealCLM
exact h1
Β· intro n
obtain β¨k, C, jβ© := h2 n
use k, C
intro x
-- actually this is also defeq so you can just combine into one
-- have h : (fun x => (Complex.ofReal β f) x) = (RCLike.ofRealLI (K := β) β f) := rfl
/-
have h'' : (fun x => (f x : β)) = (RCLike.ofRealLI (K := β) β f) := rfl
rw [h'']
-/
-- also for defeq expressions you can simply use `change`:
change βiteratedFDeriv β n (RCLike.ofRealLI β f) xβ β€ C * (1 + βxβ) ^ k
rw [LinearIsometry.norm_iteratedFDeriv_comp_left (g := RCLike.ofRealLI (K := β)) (hf := h1.contDiffAt)]
exact j x
Β· apply ENat.natCast_le_of_coe_top_le_withTop
simp only [le_refl]
also please include import Mathlib if it's a standalone lemma so others can just view it in the web playground :)
Afiq Hatta (Sep 09 2025 at 15:44):
Thanks @ZhiKai Pong - this kind of breakdown is really helpful.
Afiq Hatta (Sep 09 2025 at 15:46):
I was wondering about how to use change expressions - thank you for the flag. Need to learn more!!!
Afiq Hatta (Sep 09 2025 at 16:34):
@Joseph Tooby-Smith wrote a reply to one of the things you raised on my pull request btw
Afiq Hatta (Sep 10 2025 at 08:19):
@Joseph Tooby-Smith updated the pull request with the new proofs and also the requested refactors!
Joseph Tooby-Smith (Sep 10 2025 at 08:22):
Just approved it - I merged with master merged master into this PR to clean it up, I think you will have to wait for it to finish the workflows before you can merge it.
Afiq Hatta (Sep 10 2025 at 08:22):
sweet
Afiq Hatta (Sep 14 2025 at 09:05):
I think the next logical thing to prove would be that the Hamiltonian of the reflectionless potential satisfies
For this, I reckon we also need
- the commutuation relations
- to formalise the Hamiltonian, and also prove that it is also a Schwartz map? In terms of formalising the Hamiltonian - is there a special template that I can follow elsewhere in the code?
Also - what is the convention for what a 'ground state' here? in the paper, it is just = 0. is this a convention that we want to keep in physlean?
Joseph Tooby-Smith (Sep 14 2025 at 17:41):
I think the fact that the Hamiltonian is Schwartz should follow from the proof that the momentum operator is Schwartz and the tanh operator is.
Afiq Hatta (Sep 14 2025 at 19:17):
sweet. and in terms of the algebraic proof of the eigenvalues - i guess i can follow this quantum harmonic oscillator example as a rough guide
Last updated: Dec 20 2025 at 21:32 UTC