Zulip Chat Archive
Stream: general
Topic: Introducing Lean Finder – A Smarter Search for Lean
Wuyang (Aug 11 2025 at 20:24):
Dear Lean Users,
We DeLTA Lab (at Simon Fraser University) are building foundational tools to support mathematicians working on formal mathematics.
We are excited to introduce Lean Finder, a semantic search engine for Lean that understands latent intents behind your queries.
You can try Lean Finder in two ways:
- Web Service: With beautifully rendered LaTeX and code: https://leanfinder.github.io/
- Zulip Chat: You can simply ping our chatbot:
@leanfinder + your inquiry.
Lean Finder supports four types of input:
- Informalized statement – A full or partial natural-language description of the statement you’re looking for.
- User question – Ask in your own words, e.g., “Is there code for …” · “Why does this give an error …” · “How to define or derive instances …” · “How to finish or shorten proofs …” · “How to apply this lemma or theorem …”
- Proof state – Paste your current state directly from VS Code.
- Statement definition – Provide any fragment or complete definition.
Finally, our web service includes feedback tools. Please vote or upvote retrievals you find useful. Your feedback directly helps us improve Lean Finder, making it an even more powerful resource for the Lean and Zulip communities.
Thank you!
Sincerely,
Wuyang
Wuyang (Aug 11 2025 at 20:26):
Some examples of use cases:
@leanfinder Let L/K be a field extension and let x, y ∈ L be algebraic elements over K with the same minimal polynomial. Then the K-algebra isomorphism algEquiv between the simple field extensions K(x) and K(y) maps the generator x of K(x) to the generator y of K(y); i.e. algEquiv(x) = y.
leanfinder (Aug 11 2025 at 20:26):
Here’s what I found:
-
theorem minpoly.algEquiv_apply {x y : L} (hx : IsAlgebraic K x) (h_mp : minpoly K x = minpoly K y) : algEquiv hx h_mp (AdjoinSimple.gen K x) = AdjoinSimple.gen K y := by have hy : IsAlgebraic K y := ⟨minpoly K x, ne_zero hx.isIntegral, (h_mp ▸ aeval _ _)⟩ rw [algEquiv, trans_apply, ← adjoinRootEquivAdjoin_apply_root K hx.isIntegral, symm_apply_apply, trans_apply, AdjoinRoot.algEquivOfEq_apply_root, adjoinRootEquivAdjoin_apply_root K hy.isIntegral] "Let be a field extension and let be algebraic elements over with the same minimal polynomial. Then the -algebra isomorphism between the simple field extensions and maps the generator of to the generator of , i.e.,
" (score: 0.861) -
theorem algEquiv_apply {x y : L} (hx : IsAlgebraic K x) (h_mp : minpoly K x = minpoly K y) : algEquiv hx h_mp (AdjoinSimple.gen K x) = AdjoinSimple.gen K y := by have hy : IsAlgebraic K y := ⟨minpoly K x, ne_zero hx.isIntegral, (h_mp ▸ aeval _ _)⟩ rw [algEquiv, trans_apply, ← adjoinRootEquivAdjoin_apply_root K hx.isIntegral, symm_apply_apply, trans_apply, AdjoinRoot.algEquivOfEq_apply_root, adjoinRootEquivAdjoin_apply_root K hy.isIntegral] "Let be a field extension and let be algebraic elements over with the same minimal polynomial. Then the -algebra isomorphism between the simple field extensions and maps the generator of to the generator of , i.e., " (score: 0.859)
-
/-- The canonical
algEquivbetweenK⟮x⟯andK⟮y⟯, sendingxtoy, wherexandyhave
the same minimal polynomial overK. -/ noncomputable def algEquiv {x y : L} (hx : IsAlgebraic K x) (h_mp : minpoly K x = minpoly K y) : K⟮x⟯ ≃ₐ[K] K⟮y⟯ := by have hy : IsAlgebraic K y := ⟨minpoly K x, ne_zero hx.isIntegral, (h_mp ▸ aeval _ _)⟩ exact AlgEquiv.trans (adjoinRootEquivAdjoin K hx.isIntegral).symm (AlgEquiv.trans (AdjoinRoot.algEquivOfEq (ne_zero hx.isIntegral) h_mp) (adjoinRootEquivAdjoin K hy.isIntegral)) "Let be a field extension and let be algebraic elements over with the same minimal polynomial. Then there exists a canonical -algebra isomorphism between the simple field extensions and that maps to ." (score: 0.842) -
definition minpoly.algEquiv {x y : L} (hx : IsAlgebraic K x) (h_mp : minpoly K x = minpoly K y) : K⟮x⟯ ≃ₐ[K] K⟮y⟯ := by have hy : IsAlgebraic K y := ⟨minpoly K x, ne_zero hx.isIntegral, (h_mp ▸ aeval _ _)⟩ exact AlgEquiv.trans (adjoinRootEquivAdjoin K hx.isIntegral).symm (AlgEquiv.trans (AdjoinRoot.algEquivOfEq (ne_zero hx.isIntegral) h_mp) (adjoinRootEquivAdjoin K hy.isIntegral)) "Given a field extension and two elements that are algebraic over with the same minimal polynomial, there exists a -algebra isomorphism between the intermediate fields and . This isomorphism maps the generator of to the generator of ." (score: 0.834)
-
theorem algEquivOfEq_apply_root {p q : K[X]} (hp : p ≠ 0) (h_eq : p = q) : algEquivOfEq hp h_eq (root p) = root q := by rw [← coe_algHom, algEquivOfEq_toAlgHom, liftHom_root] "Let be a field and let be nonzero polynomials such that . The algebra isomorphism from to maps the adjoined root of to the adjoined root of , i.e., " (score: 0.791)
-
theorem minpoly.exists_algEquiv_of_root [Normal K L] {x y : L} (hy : IsAlgebraic K y) (h_ev : (Polynomial.aeval x) (minpoly K y) = 0) : ∃ σ : L ≃ₐ[K] L, σ x = y := by have hx : IsAlgebraic K x := ⟨minpoly K y, ne_zero hy.isIntegral, h_ev⟩ set f : K⟮x⟯ ≃ₐ[K] K⟮y⟯ := algEquiv hx (eq_of_root hy h_ev) have hxy : (liftNormal f L) ((algebraMap (↥K⟮x⟯) L) (AdjoinSimple.gen K x)) = y := by rw [liftNormal_commutes f L, algEquiv_apply, AdjoinSimple.algebraMap_gen K y] exact ⟨(liftNormal f L), hxy⟩ "Let be a normal field extension, and let be elements such that is algebraic over and is a root of the minimal polynomial of over . Then there exists a -algebra automorphism such that ." (score: 0.790)
-
theorem exists_algEquiv_of_root [Normal K L] {x y : L} (hy : IsAlgebraic K y) (h_ev : (Polynomial.aeval x) (minpoly K y) = 0) : ∃ σ : L ≃ₐ[K] L, σ x = y := by have hx : IsAlgebraic K x := ⟨minpoly K y, ne_zero hy.isIntegral, h_ev⟩ set f : K⟮x⟯ ≃ₐ[K] K⟮y⟯ := algEquiv hx (eq_of_root hy h_ev) have hxy : (liftNormal f L) ((algebraMap (↥K⟮x⟯) L) (AdjoinSimple.gen K x)) = y := by rw [liftNormal_commutes f L, algEquiv_apply, AdjoinSimple.algebraMap_gen K y] exact ⟨(liftNormal f L), hxy⟩ "Let be a normal field extension, and let be algebraic over . If is a root of the minimal polynomial of over , then there exists a -algebra isomorphism such that . This means and are Galois conjugates." (score: 0.789)
-
theorem minpoly.exists_algEquiv_of_root' [Normal K L] {x y : L} (hy : IsAlgebraic K y) (h_ev : (Polynomial.aeval x) (minpoly K y) = 0) : ∃ σ : L ≃ₐ[K] L, σ y = x := by obtain ⟨σ, hσ⟩ := exists_algEquiv_of_root hy h_ev use σ.symm rw [← hσ, symm_apply_apply] "Let be a normal field extension, and let be elements such that is algebraic over and is a root of the minimal polynomial of over . Then there exists a -algebra automorphism such that ." (score: 0.782)
-
theorem AdjoinRoot.algEquivOfEq_apply_root {p q : K[X]} (hp : p ≠ 0) (h_eq : p = q) : algEquivOfEq hp h_eq (root p) = root q := by rw [← coe_algHom, algEquivOfEq_toAlgHom, liftHom_root] "Let be a field and let be nonzero polynomials such that . The algebra isomorphism from to maps the adjoined root of to the adjoined root of , i.e.,
" (score: 0.780) -
theorem algEquivOfAssociated_apply_root {p q : K[X]} (hp : p ≠ 0) (hpq : Associated p q) : algEquivOfAssociated hp hpq (root p) = root q := by rw [← coe_algHom, algEquivOfAssociated_toAlgHom, liftHom_root] "Let be a field and let be nonzero associated polynomials. If is an algebra equivalence, then the adjoined root of is mapped to the adjoined root of under this equivalence." (score: 0.780)
Wuyang (Aug 11 2025 at 20:27):
@leanfinder K : Type u_1
E : Type u_2
inst✝ : RCLike K
z✝ z : K
⊢ |re z| ≤ ‖z‖
Transform the goal from proving that the absolute value of the real part of a complex number is less than or equal to its norm, to proving that the square of the real part is less than or equal to the squared norm of the number.
leanfinder (Aug 11 2025 at 20:27):
Here’s what I found:
-
theorem RCLike.abs_re_le_norm (z : K) : |re z| ≤ ‖z‖ := by rw [mul_self_le_mul_self_iff (abs_nonneg _) (norm_nonneg _), abs_mul_abs_self, mul_self_norm] apply re_sq_le_normSq "For any element in a real-complex like field (where is either or ), the absolute value of its real part is bounded by its norm, i.e., ." (score: 0.797)
-
theorem RCLike.normSq_eq_def' (z : K) : normSq z = ‖z‖ ^ 2 := norm_sq_eq_def.symm "For any element in an
RCLikefield (which is either or ), the squared norm equals the square of its norm, i.e.,
" (score: 0.793) -
theorem sq_le_sq : a ^ 2 ≤ b ^ 2 ↔ |a| ≤ |b| := by simpa only [sq_abs] using sq_le_sq₀ (abs_nonneg a) (abs_nonneg b) "For any elements and in a linearly ordered ring , the square of is less than or equal to the square of if and only if the absolute value of is less than or equal to the absolute value of , i.e., ." (score: 0.791)
-
theorem RCLike.re_le_norm (z : K) : re z ≤ ‖z‖ := (abs_le.1 (abs_re_le_norm z)).2 "For any element in a real-complex like field (where is either or ), the real part of is bounded by its norm, i.e., ." (score: 0.790)
-
theorem RCLike.norm_re_le_norm (z : K) : ‖re z‖ ≤ ‖z‖ := abs_re_le_norm z "For any element in a real-complex like field (where is either or ), the norm of its real part is bounded by its norm, i.e., ." (score: 0.790)
-
theorem RCLike.re_sq_le_normSq (z : K) : re z * re z ≤ normSq z := le_add_of_nonneg_right (mul_self_nonneg _) "For any element in a real-complex like field (where is either or ), the square of its real part is less than or equal to its squared norm, i.e., ." (score: 0.790)
-
theorem Real.le_sqrt (hx : 0 ≤ x) (hy : 0 ≤ y) : x ≤ √y ↔ x ^ 2 ≤ y := le_iff_le_iff_lt_iff_lt.2 <| sqrt_lt hy hx "For any nonnegative real numbers and , the inequality holds if and only if ." (score: 0.786)
-
theorem sq_abs (a : α) : |a| ^ 2 = a ^ 2 := by simpa only [sq] using abs_mul_abs_self a "For any element in a linearly ordered ring , the square of the absolute value of equals the square of , i.e., ." (score: 0.786)
-
theorem RCLike.sqrt_normSq_eq_norm {z : K} : √(normSq z) = ‖z‖ := by rw [normSq_eq_def', Real.sqrt_sq (norm_nonneg _)] "For any element in an
RCLikefield (which is either or ), the square root of its squared norm equals its norm, i.e.,
" (score: 0.785) -
theorem RCLike.mul_self_norm (z : K) : ‖z‖ * ‖z‖ = normSq z := by rw [normSq_eq_def', sq] "For any element in an
RCLikefield (which is either or ), the product of the norm of with itself equals the squared norm of , i.e.,
" (score: 0.779)
Matthew Ballard (Aug 11 2025 at 20:31):
@Wuyang Don't cross post
Wuyang (Aug 11 2025 at 20:32):
Matthew Ballard said:
Wuyang Don't cross post
No more! I just posted in general and new members. Hope that could be fine.
Matthew Ballard (Aug 11 2025 at 20:32):
I have removed your post in #new members. Don't cross post.
Eric Wieser (Aug 11 2025 at 22:10):
Some initial feedback; this output is way too verbose to be suitable for zulip; I suggest following the loogle bot and giving a one-line summary and a link to the webpage.
Eric Wieser (Aug 11 2025 at 22:11):
Showing the proof for each theorem is also very strange, as this is not relevant at all when trying to search for a theorem to apply.
Wuyang (Aug 12 2025 at 19:01):
@Eric Wieser Thank you very much for this valuable feedback! It took me some time to integrate this change.
I give an example below. Do you like this format?
Wuyang (Aug 12 2025 at 19:01):
@leanfinder Let L/K be a field extension and let x, y ∈ L be algebraic elements over K with the same minimal polynomial. Then the K-algebra isomorphism algEquiv between the simple field extensions K(x) and K(y) maps the generator x of K(x) to the generator y of K(y); i.e. algEquiv(x) = y.
leanfinder (Aug 12 2025 at 19:01):
Here’s what I found:
minpoly.algEquiv_apply (score: 0.868)
algEquiv_apply (score: 0.865)
minpoly.algEquiv (score: 0.844)
More Retrievals...
Wuyang (Aug 12 2025 at 19:04):
@Eric Wieser One thing to note here is that we support more informative docstrings than mathlib. You may have noticed that many statements in mathlib have very short, or even no docstrings. This may confuse new members. Lean Finder will provide more detailed descriptions for all statements, which I have now put into the spoiler.
Kenny Lau (Aug 12 2025 at 19:45):
it feels like your queries are LLM-generated, is there a specific algorithm you used? is this available in Leanfinder? Leansearch also features an LLM feature called "augmentation"
Wuyang (Aug 12 2025 at 19:53):
@Kenny Lau Thanks!
You don't need to use LLM to augment your query.
Quantitatively, Lean Finder achieves higher retrieval rates on mathlib4 than Lean Search, even with their "augmentation" feature:
- LeanSearch: 0.487
- Lean Finder: 0.620
Below I am using another query, which came from a vote submitted by an active user.
@leanfinder Theorem to show that if n is a positive integer, then 1/n is positive
leanfinder (Aug 12 2025 at 19:53):
Here’s what I found:
lemma (score: 0.700)
succ_ge_zero(k (score: 0.699)
Nat.cast_pos (score: 0.699)
More Retrievals...
Jireh Loreaux (Aug 12 2025 at 20:11):
@Wuyang note that there is something screwy in the links (the first one is called "lemma" and links to docs#pow_pos, the second one is clearly misnamed too, and even more strangely, it links to a file in a completely different repository: https://github.com/optsuite/optlib/blob/26fcefb31b5aee7f7f5fc7194f462b437282675f/Optlib/Convex/ImageSubgradientClosed.lean, which contains a lemma succ_ge_zero)
Wuyang (Aug 12 2025 at 20:18):
@Jireh Loreaux Thanks!
- The first one seems have some weird rendering issue, which I will dig more
- Another feature of Lean Finder is that, it supports statements beyond mathlib. We can retrieve from more 3rd party contributions:
- SciLean (https://github.com/lecopivo/SciLean)
- A formalization of Borel determinacy in Lean (Manthe, 2025) (https://github.com/sven-manthe/A-formalization-of-Borel-determinacy-in-Lean)
- Optlib (Li et al., 2025a;b) (https://github.com/optsuite/optlib)
- Formalising Fermat’s Last Theorem for Exponent 3 (Monticone, 2024) (https://github.com/riccardobrasca/flt3)
- Formalisation of constructable numbers (Monnerjahn, 2024) (https://github.com/Louis-Le-Grand/Formalisation-of-constructable-numbers)
Wuyang (Aug 12 2025 at 20:18):
(deleted)
Wuyang (Aug 12 2025 at 20:19):
@leanfinder Theorem to show that if n is a positive integer, then 1/n is positive
leanfinder (Aug 12 2025 at 20:19):
Here’s what I found:
Nat.one_div_pos_of_nat (score: 0.762)
Nat.one_div_cast_pos (score: 0.762)
PNat.pos (score: 0.757)
More Retrievals...
Wuyang (Aug 12 2025 at 20:19):
@Jireh Loreaux now the rendering works :point_up:
Jireh Loreaux (Aug 12 2025 at 20:20):
Why are the scores different on this run versus the last one?
Wuyang (Aug 12 2025 at 20:21):
@Jireh Loreaux I think we have to call Lean Finder in separate messages instead of being mixed with other irrelevant text
Last updated: Dec 20 2025 at 21:32 UTC