Skip to content

Commit 107260a

Browse files
committed
Merge branch 'master' into mem_sobolev
2 parents a61f90c + 4ec5d95 commit 107260a

File tree

14 files changed

+56
-247
lines changed

14 files changed

+56
-247
lines changed

.github/workflows/build_template.yml

Lines changed: 7 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -247,76 +247,6 @@ jobs:
247247
echo "✅ All inputRevs in lake-manifest.json are valid"
248248
fi
249249
250-
- name: validate ProofWidgets source repository
251-
# Only enforce this on the main mathlib4 repository, not on nightly-testing
252-
if: github.repository == 'leanprover-community/mathlib4'
253-
shell: bash
254-
run: |
255-
cd pr-branch
256-
257-
expected_url='https://github.com/leanprover-community/ProofWidgets4'
258-
proofwidgets_count=$(jq '[.packages[] | select(.name == "proofwidgets")] | length' lake-manifest.json)
259-
if [ "$proofwidgets_count" -ne 1 ]; then
260-
echo "❌ Error: expected exactly one proofwidgets entry in lake-manifest.json, found $proofwidgets_count"
261-
exit 1
262-
fi
263-
264-
proofwidgets_url=$(jq -r '.packages[] | select(.name == "proofwidgets") | .url' lake-manifest.json)
265-
normalized_url="${proofwidgets_url%.git}"
266-
if [ "$normalized_url" != "$expected_url" ]; then
267-
echo "❌ Error: invalid ProofWidgets source URL in lake-manifest.json"
268-
echo " expected: $expected_url"
269-
echo " found: $proofwidgets_url"
270-
exit 1
271-
fi
272-
273-
echo "✅ ProofWidgets source URL is allowed: $proofwidgets_url"
274-
275-
- name: verify ProofWidgets lean-toolchain matches on versioned releases
276-
# Only enforce this on the main mathlib4 repository, not on nightly-testing
277-
if: github.repository == 'leanprover-community/mathlib4'
278-
shell: bash
279-
run: |
280-
cd pr-branch
281-
282-
# Read the lean-toolchain file
283-
TOOLCHAIN=$(cat lean-toolchain | tr -d '[:space:]')
284-
echo "Lean toolchain: $TOOLCHAIN"
285-
286-
# Check if toolchain matches the versioned release pattern: leanprover/lean4:vX.Y.Z (with optional suffix like -rc1)
287-
if [[ "$TOOLCHAIN" =~ ^leanprover/lean4:v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
288-
echo "✓ Detected versioned Lean release: $TOOLCHAIN"
289-
echo "Verifying ProofWidgets lean-toolchain matches..."
290-
291-
# Check if ProofWidgets lean-toolchain exists
292-
if [ ! -f .lake/packages/proofwidgets/lean-toolchain ]; then
293-
echo "❌ Error: .lake/packages/proofwidgets/lean-toolchain does not exist"
294-
echo "This file should be created by 'lake env' during dependency download."
295-
exit 1
296-
fi
297-
298-
# Read ProofWidgets lean-toolchain
299-
PROOFWIDGETS_TOOLCHAIN=$(cat .lake/packages/proofwidgets/lean-toolchain | tr -d '[:space:]')
300-
echo "ProofWidgets toolchain: $PROOFWIDGETS_TOOLCHAIN"
301-
302-
# Compare the two
303-
if [ "$TOOLCHAIN" != "$PROOFWIDGETS_TOOLCHAIN" ]; then
304-
echo "❌ Error: Lean toolchain mismatch!"
305-
echo " Main lean-toolchain: $TOOLCHAIN"
306-
echo " ProofWidgets lean-toolchain: $PROOFWIDGETS_TOOLCHAIN"
307-
echo ""
308-
echo "When using a versioned Lean release (leanprover/lean4:vX.Y.Z),"
309-
echo "the ProofWidgets dependency must use the same toolchain."
310-
echo "Please update the ProofWidgets dependency to use $TOOLCHAIN"
311-
exit 1
312-
else
313-
echo "✅ ProofWidgets lean-toolchain matches: $TOOLCHAIN"
314-
fi
315-
else
316-
echo "ℹ Lean toolchain is not a versioned release (pattern: leanprover/lean4:vX.Y.Z)"
317-
echo "Skipping ProofWidgets toolchain verification."
318-
fi
319-
320250
- name: get cache (1/3 - setup and initial fetch)
321251
id: get_cache_part1_setup
322252
shell: bash # only runs `cache get` from `tools-branch`, so doesn't need to be inside landrun
@@ -327,7 +257,7 @@ jobs:
327257
328258
# Fail quickly if the cache is completely cold, by checking for Mathlib.Init
329259
echo "Attempting to fetch olean for Mathlib/Init.lean from cache..."
330-
../tools-branch/.lake/build/bin/cache --skip-proofwidgets get Mathlib/Init.lean
260+
../tools-branch/.lake/build/bin/cache get Mathlib/Init.lean
331261
332262
- name: get cache (2/3 - test Mathlib.Init cache)
333263
id: get_cache_part2_test
@@ -381,9 +311,9 @@ jobs:
381311
echo "Warming up cache using previous commit: $PREV_SHA (source: $PREV_SHA_SOURCE)"
382312
if git cat-file -e "$PREV_SHA^{commit}" 2>/dev/null || git fetch --no-tags --depth=1 origin "$PREV_SHA"; then
383313
git checkout "$PREV_SHA"
384-
../tools-branch/.lake/build/bin/cache --skip-proofwidgets get
314+
../tools-branch/.lake/build/bin/cache get
385315
# Run again with --repo, to ensure we actually get the oleans.
386-
../tools-branch/.lake/build/bin/cache --repo="$CACHE_REPO" --skip-proofwidgets get
316+
../tools-branch/.lake/build/bin/cache --repo="$CACHE_REPO" get
387317
388318
echo "Switching back to branch head"
389319
git checkout "$ORIG_SHA"
@@ -396,18 +326,10 @@ jobs:
396326
397327
echo "Fetching all remaining cache..."
398328
399-
../tools-branch/.lake/build/bin/cache --skip-proofwidgets get
329+
../tools-branch/.lake/build/bin/cache get
400330
401331
# Run again with --repo, to ensure we actually get the oleans.
402-
../tools-branch/.lake/build/bin/cache --repo="$CACHE_REPO" --skip-proofwidgets get
403-
404-
- name: fetch ProofWidgets release
405-
# We need network access for ProofWidgets frontend assets.
406-
# Run inside landrun so PR-controlled code remains sandboxed.
407-
shell: landrun --unrestricted-network --rox /etc --rox /usr --rw /dev --rox /home/lean/.elan --rox /home/lean/actions-runner/_work --rw pr-branch/.lake/ --env PATH --env HOME --env GITHUB_OUTPUT --env CI -- bash -euxo pipefail {0}
408-
run: |
409-
cd pr-branch
410-
lake build proofwidgets:release
332+
../tools-branch/.lake/build/bin/cache --repo="$CACHE_REPO" get
411333
412334
- name: update {Mathlib, Tactic, Counterexamples, Archive}.lean
413335
id: mk_all
@@ -462,8 +384,8 @@ jobs:
462384
shell: bash
463385
run: |
464386
cd pr-branch
465-
../tools-branch/.lake/build/bin/cache --skip-proofwidgets get Archive.lean
466-
../tools-branch/.lake/build/bin/cache --skip-proofwidgets get Counterexamples.lean
387+
../tools-branch/.lake/build/bin/cache get Archive.lean
388+
../tools-branch/.lake/build/bin/cache get Counterexamples.lean
467389
468390
- name: build archive
469391
id: archive

Cache/IO.lean

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,12 @@ def rootHashGeneration : UInt64 := 4
122122
folders are located. However, `lake` has multiple options to customise these paths, like
123123
setting `srcDir` in a `lean_lib`. See `mkBuildPaths` below which currently assumes
124124
that no such options are set in any mathlib dependency)
125-
* the build directory for proofwidgets
126125
-/
127126
structure CacheM.Context where
128127
/-- source directory for mathlib files -/
129128
mathlibDepPath : FilePath
130129
/-- the Lean source search path -/
131130
srcSearchPath : SearchPath
132-
/-- build directory for proofwidgets -/
133-
proofWidgetsBuildDir : FilePath
134131

135132
@[inherit_doc CacheM.Context]
136133
abbrev CacheM := ReaderT CacheM.Context IO
@@ -158,8 +155,7 @@ private def CacheM.getContext : IO CacheM.Context := do
158155
let mathlibSource ← CacheM.mathlibDepPath sp
159156
return {
160157
mathlibDepPath := mathlibSource,
161-
srcSearchPath := sp,
162-
proofWidgetsBuildDir := LAKEPACKAGESDIR / "proofwidgets" / ".lake" / "build"}
158+
srcSearchPath := sp}
163159

164160
/-- Run a `CacheM` in `IO` by loading the context from `LEAN_SRC_PATH`. -/
165161
def CacheM.run (f : CacheM α) : IO α := do ReaderT.run f (← getContext)

Cache/Main.lean

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ Commands:
3939
Options:
4040
--repo=OWNER/REPO Override the repository to fetch/push cache from
4141
--staging-dir=<output-directory> Required for 'stage', 'stage!', 'unstage' and 'put-staged': staging directory.
42-
--skip-proofwidgets Skip fetching/building ProofWidgets release assets during 'get'
4342
4443
* Linked files refer to local cache files with corresponding Lean sources
4544
* Commands ending with '!' should be used manually, when hot-fixes are needed
@@ -101,7 +100,6 @@ def main (args : List String) : IO Unit := do
101100
-- parse relevant options, ignore the rest
102101
let repo? ← parseNamedOpt "repo" options
103102
let stagingDir? ← parseNamedOpt "staging-dir" options
104-
let skipProofWidgets := parseFlagOpt "skip-proofwidgets" options
105103

106104
let mut roots : Std.HashMap Lean.Name FilePath ← parseArgs args
107105
if roots.isEmpty then do
@@ -118,7 +116,7 @@ def main (args : List String) : IO Unit := do
118116
if leanTarArgs.contains (args.headD "") then validateLeanTar
119117
let get (args : List String) (force := false) (decompress := true) := do
120118
let hashMap ← if args.isEmpty then pure hashMap else hashMemo.filterByRootModules roots.keys
121-
getFiles repo? hashMap force force goodCurl decompress skipProofWidgets
119+
getFiles repo? hashMap force force goodCurl decompress
122120
let pack (overwrite verbose unpackedOnly := false) := do
123121
packCache hashMap overwrite verbose unpackedOnly (← getGitCommitHash)
124122
let put (overwrite unpackedOnly := false) := do

Cache/Requests.lean

Lines changed: 1 addition & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -641,61 +641,15 @@ def checkForManifestMismatch : IO.CacheM Unit := do
641641
precedence, then run `lake update`."
642642
IO.Process.exit 1
643643

644-
/-- Fetches the ProofWidgets cloud release and prunes non-JS files. -/
645-
def getProofWidgets (buildDir : FilePath) : IO Unit := do
646-
if (← buildDir.pathExists) then
647-
-- Check if the ProofWidgets build is out-of-date via `lake`.
648-
-- This is done through Lake as cache has no simple heuristic
649-
-- to determine whether the ProofWidgets JS is out-of-date.
650-
let out ← IO.Process.output
651-
{cmd := "lake", args := #["-v", "build", "--no-build", "proofwidgets:release"]}
652-
if out.exitCode == 0 then -- up-to-date
653-
return
654-
else if out.exitCode == 3 then -- needs fetch (`--no-build` triggered)
655-
pure ()
656-
else
657-
printLakeOutput out
658-
throw <| IO.userError s!"Failed to validate ProofWidgets cloud release: \
659-
lake failed with error code {out.exitCode}"
660-
-- Download and unpack the ProofWidgets cloud release (for its `.js` files)
661-
IO.print "Fetching ProofWidgets cloud release..."
662-
let out ← IO.Process.output
663-
{cmd := "lake", args := #["-v", "build", "proofwidgets:release"]}
664-
if out.exitCode == 0 then
665-
IO.println " done!"
666-
else
667-
IO.print "\n"
668-
printLakeOutput out
669-
throw <| IO.userError s!"Failed to fetch ProofWidgets cloud release: \
670-
lake failed with error code {out.exitCode}"
671-
-- Prune non-JS ProofWidgets files (e.g., `olean`, `.c`)
672-
try
673-
IO.FS.removeDirAll (buildDir / "lib")
674-
IO.FS.removeDirAll (buildDir / "ir")
675-
catch e =>
676-
throw <| IO.userError s!"Failed to prune ProofWidgets cloud release: {e}"
677-
where
678-
printLakeOutput out := do
679-
unless out.stdout.isEmpty do
680-
IO.eprintln "lake stdout:"
681-
IO.eprint out.stdout
682-
unless out.stderr.isEmpty do
683-
IO.eprintln "lake stderr:"
684-
IO.eprint out.stderr
685-
686644
/-- Downloads missing files, and unpacks files. -/
687645
def getFiles
688646
(repo? : Option String) (hashMap : IO.ModuleHashMap)
689-
(forceDownload forceUnpack parallel decompress skipProofWidgets : Bool)
647+
(forceDownload forceUnpack parallel decompress : Bool)
690648
: IO.CacheM Unit := do
691649
let isMathlibRoot ← IO.isMathlibRoot
692650
unless isMathlibRoot do
693651
checkForToolchainMismatch
694652
checkForManifestMismatch
695-
if skipProofWidgets then
696-
IO.println "Skipping ProofWidgets release fetch"
697-
else
698-
getProofWidgets (← read).proofWidgetsBuildDir
699653

700654
let mathlibDepPath := (← read).mathlibDepPath
701655

Mathlib/Computability/Primrec/Basic.lean

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,11 @@ def subtype {p : α → Prop} [DecidablePred p] (hp : PrimrecPred p) : Primcodab
822822
by_cases h : p a <;> simp [h]; rfl⟩
823823

824824
instance fin {n} : Primcodable (Fin n) :=
825-
@ofEquiv _ _ (subtype <| nat_lt.comp .id (const n)) Fin.equivSubtype
825+
letI : Primcodable { i : ℕ // i < n } := subtype <| nat_lt.comp .id (const n)
826+
ofEquiv { i : ℕ // i < n } Fin.equivSubtype
827+
828+
example (n) : (fin (n := n)).toEncodable = Fin.encodable n := by
829+
with_reducible_and_instances rfl
826830

827831
section ULower
828832

@@ -889,7 +893,7 @@ theorem ulower_up : Primrec (ULower.up : ULower α → α) :=
889893
option_get (Primrec.decode₂.comp subtype_val)
890894

891895
theorem fin_val_iff {n} {f : α → Fin n} : (Primrec fun a => (f a).1) ↔ Primrec f := by
892-
letI : Primcodable { a // id a < n } := Primcodable.subtype (nat_lt.comp .id (const _))
896+
letI : Primcodable { a // a < n } := Primcodable.subtype (nat_lt.comp .id (const _))
893897
exact (Iff.trans (by rfl) subtype_val_iff).trans (of_equiv_iff _)
894898

895899
theorem fin_val {n} : Primrec (fun (i : Fin n) => (i : ℕ)) :=

Mathlib/Computability/RegularExpressions.lean

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ public import Mathlib.Tactic.AdaptationNote
1212
# Regular Expressions
1313
1414
This file contains the formal definition for regular expressions and basic lemmas. Note these are
15-
regular expressions in terms of formal language theory. Note this is different to regex's used in
15+
regular expressions in terms of formal language theory. Note this is different to regexes used in
1616
computer science such as the POSIX standard.
1717
1818
## TODO
1919
20-
Currently, we don't show that regular expressions and DFA/NFA's are equivalent.
20+
Currently, we do not show that regular expressions and DFAs/NFAs are equivalent.
2121
Multiple competing PRs towards that goal are in review.
2222
See https://leanprover.zulipchat.com/#narrow/channel/287929-mathlib4/topic/Regular.20languages.3A.20the.20review.20queue
2323
-/
@@ -35,13 +35,13 @@ variable {α β γ : Type*}
3535
-- Disable generation of unneeded lemmas which the simpNF linter would complain about.
3636
set_option genSizeOfSpec false in
3737
set_option genInjectivity false in
38-
/-- This is the definition of regular expressions. The names used here is to mirror the definition
39-
of a Kleene algebra (https://en.wikipedia.org/wiki/Kleene_algebra).
38+
/-- This is the definition of regular expressions. The names used here are meant to mirror the
39+
definition of a Kleene algebra (https://en.wikipedia.org/wiki/Kleene_algebra).
4040
* `0` (`zero`) matches nothing
4141
* `1` (`epsilon`) matches only the empty string
4242
* `char a` matches only the string 'a'
43-
* `star P` matches any finite concatenation of strings which match `P`
44-
* `P + Q` (`plus P Q`) matches anything which match `P` or `Q`
43+
* `star P` matches any finite concatenation of strings that match `P`
44+
* `P + Q` (`plus P Q`) matches anything that matches `P` or `Q`
4545
* `P * Q` (`comp P Q`) matches `x ++ y` if `x` matches `P` and `y` matches `Q`
4646
-/
4747
inductive RegularExpression (α : Type u) : Type u

Mathlib/Geometry/Polygon/Basic.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@ theorem HasNondegenerateVertices.hasNondegenerateEdges [NeZero n] [Nontrivial R]
8484
(h : poly.HasNondegenerateVertices R) : poly.HasNondegenerateEdges := by
8585
obtain ⟨m, rfl⟩ := Nat.exists_eq_succ_of_ne_zero (NeZero.ne n)
8686
intro i
87-
simp only [finRotate_succ_apply]
8887
simpa using (h i).injective.ne (by decide : (0 : Fin 3) ≠ 1)
8988

9089
theorem HasNondegenerateVertices.three_le [NeZero n] [Nontrivial R] {poly : Polygon P n}

Mathlib/Logic/Equiv/Fin/Rotate.lean

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -64,27 +64,34 @@ theorem Fin.snoc_eq_cons_rotate {α : Type*} (v : Fin n → α) (a : α) :
6464
theorem finRotate_one : finRotate 1 = Equiv.refl _ :=
6565
Subsingleton.elim _ _
6666

67-
@[simp] theorem finRotate_succ_apply (i : Fin (n + 1)) : finRotate (n + 1) i = i + 1 := by
68-
cases n
69-
· exact @Subsingleton.elim (Fin 1) _ _ _
70-
obtain rfl | h := Fin.eq_or_lt_of_le i.le_last
71-
· simp [finRotate_last]
72-
· cases i
73-
simp only [Fin.lt_def, Fin.val_last] at h
74-
simp [finRotate_of_lt h, Fin.add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ h)]
67+
@[simp]
68+
theorem finRotate_apply (i : Fin n) : haveI := i.neZero; finRotate n i = i + 1 := by
69+
match n with
70+
| 0 => exact i.elim0
71+
| 1 => exact @Subsingleton.elim (Fin 1) _ _ _
72+
| n + 2 =>
73+
obtain rfl | h := Fin.eq_or_lt_of_le i.le_last
74+
· simp [finRotate_last]
75+
· cases i
76+
simp only [Fin.lt_def, Fin.val_last] at h
77+
simp [finRotate_of_lt h, Fin.add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ h)]
78+
79+
@[deprecated finRotate_apply (since := "2026-03-29")]
80+
theorem finRotate_succ_apply (i : Fin (n + 1)) : finRotate (n + 1) i = i + 1 := by
81+
simp
7582

7683
theorem finRotate_apply_zero : finRotate n.succ 0 = 1 := by
7784
simp
7885

7986
theorem coe_finRotate_of_ne_last {i : Fin n.succ} (h : i ≠ Fin.last n) :
8087
(finRotate (n + 1) i : ℕ) = i + 1 := by
81-
rw [finRotate_succ_apply]
88+
rw [finRotate_apply]
8289
have : (i : ℕ) < n := Fin.val_lt_last h
8390
exact Fin.val_add_one_of_lt this
8491

8592
theorem coe_finRotate (i : Fin n.succ) :
8693
(finRotate n.succ i : ℕ) = if i = Fin.last n then (0 : ℕ) else i + 1 := by
87-
rw [finRotate_succ_apply, Fin.val_add_one i]
94+
rw [finRotate_apply, Fin.val_add_one i]
8895

8996
theorem lt_finRotate_iff_ne_last (i : Fin (n + 1)) :
9097
i < finRotate _ i ↔ i ≠ Fin.last n := by
@@ -95,14 +102,19 @@ theorem lt_finRotate_iff_ne_neg_one [NeZero n] (i : Fin n) :
95102
obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero (NeZero.ne n)
96103
rw [lt_finRotate_iff_ne_last, ne_eq, not_iff_not, ← Fin.neg_last, neg_neg]
97104

98-
@[simp] lemma finRotate_succ_symm_apply [NeZero n] (i : Fin n) : (finRotate _).symm i = i - 1 := by
99-
obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero (NeZero.ne n)
105+
@[simp]
106+
lemma finRotate_symm_apply (i : Fin n) : haveI := i.neZero; (finRotate _).symm i = i - 1 := by
107+
obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero i.pos.ne'
100108
apply (finRotate n.succ).symm_apply_eq.mpr
101-
rw [finRotate_succ_apply, sub_add_cancel]
109+
rw [finRotate_apply, sub_add_cancel]
110+
111+
@[deprecated finRotate_symm_apply (since := "2026-03-29")]
112+
lemma finRotate_succ_symm_apply [NeZero n] (i : Fin n) : (finRotate _).symm i = i - 1 := by
113+
simp
102114

103115
lemma coe_finRotate_symm_of_ne_zero [NeZero n] {i : Fin n} (hi : i ≠ 0) :
104116
((finRotate _).symm i : ℕ) = i - 1 := by
105-
rwa [finRotate_succ_symm_apply, Fin.val_sub_one_of_ne_zero]
117+
rwa [finRotate_symm_apply, Fin.val_sub_one_of_ne_zero]
106118

107119
theorem finRotate_symm_lt_iff_ne_zero [NeZero n] (i : Fin n) :
108120
(finRotate _).symm i < i ↔ i ≠ 0 := by
@@ -128,5 +140,5 @@ lemma finCycle_eq_finRotate_iterate {k : Fin n} : finCycle k = (finRotate n)^[k.
128140
| zero => simp
129141
| succ k ih =>
130142
rw [Fin.val_eq_val, Fin.val_castSucc] at ih
131-
rw [Fin.val_succ, Function.iterate_succ', Function.comp_apply, ← ih, finRotate_succ_apply,
143+
rw [Fin.val_succ, Function.iterate_succ', Function.comp_apply, ← ih, finRotate_apply,
132144
finCycle_apply, finCycle_apply, add_assoc, Fin.coeSucc_eq_succ]

Mathlib/Tactic/CategoryTheory/Coherence/Normalize.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ the concept of strict monoidal categories due to the feature of dependent type t
3737
normalization tactic can remove associators and unitors from the expression, extracting the
3838
necessary data for drawing string diagrams.
3939
40-
The string diagrams widget is to use Penrose (https://github.com/penrose) via ProofWidget.
40+
The string diagrams widget is to use Penrose (https://github.com/penrose) via ProofWidgets.
4141
However, it should be noted that the normalization procedure in this file does not rely on specific
4242
settings, allowing for broader application. Future plans include the following. At least I (Yuma)
4343
would like to work on these in the future, but it might not be immediate. If anyone is interested,

0 commit comments

Comments
 (0)