Skip to content

Commit 66d1ce1

Browse files
Merge branch 'master' into Frullani_integral
2 parents f58e0a8 + fb6b1ce commit 66d1ce1

3,850 files changed

Lines changed: 26469 additions & 15515 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.git-blame-ignore-revs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
fc48848e4374f13c796a7399bfccd2e228f776df
55
# 2025-11-19 move Mathlib to the module system (#31786)
66
6a54a80825b060ab20dc31751ebdce78b3a3b518
7+
# 2025-12-01 fix spelling in doc-strings (#32286)
8+
b728e1450a53133aa4171eeadc0bc8d3ee58415c

.github/actions/get-mathlib-ci/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ inputs:
1010
# Default pinned commit used by workflows unless they explicitly override.
1111
# Update this ref as needed to pick up changes to mathlib-ci scripts
1212
# This is also updated automatically by .github/workflows/update_dependencies.yml
13-
default: 0cd6cbc879d9241f3b4f6cb7e8291e34128c5654
13+
default: 5668fbbccf0fecefdfcddf539b8406db197dfc59
1414
path:
1515
description: Checkout destination path.
1616
required: false

.github/workflows/lake_cache_shadow.yml

Lines changed: 112 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,38 @@ name: Lake cache shadow (master)
1919
# # host than the S3 API endpoint; e.g. an R2 public r2.dev/custom domain).
2020
# LAKE_CACHE_ARTIFACT_ENDPOINT_PUBLIC — e.g. https://pub-<hash>.r2.dev/<prefix>/artifacts
2121
# LAKE_CACHE_REVISION_ENDPOINT_PUBLIC — e.g. https://pub-<hash>.r2.dev/<prefix>/revisions
22+
# # Optional. Default toolchain override for every run, including
23+
# # scheduled ones; the dispatch input takes precedence. Unset to run
24+
# # on the repo pin.
25+
# LAKE_SHADOW_TOOLCHAIN_OVERRIDE — e.g. leanprover/lean4-pr-releases:pr-release-14301
2226
#
2327
# Jobs:
2428
# build_and_stage Build mathlib + deps with Lake's artifact cache
2529
# enabled, then stage the resulting .ltar files.
2630
# upload Push staged artifacts to the cache bucket via
2731
# `lake cache put-staged`, then record a per-run manifest
28-
# under cache/analysis/ and report carryover vs the prior run.
32+
# under cache/analysis/<toolchain-slug>/ and report
33+
# carryover vs the prior run on the same toolchain.
2934
# consume Fresh checkout, fetch from the cache bucket via
3035
# `lake cache get`, run `lake build` against the
3136
# rehydrated cache, then verify with `--rehash`.
3237
# report Post a per-run summary to the `CI admins` Zulip
3338
# stream (topic `Lake cache shadow`).
39+
#
40+
# Toolchain override:
41+
# The `toolchain_override` input, or else the LAKE_SHADOW_TOOLCHAIN_OVERRIDE
42+
# variable, swaps the toolchain the whole pipeline runs on: build_and_stage
43+
# resolves it into its `toolchain` output, and the downstream jobs stamp
44+
# that output into their checkouts, so every job runs the same lake. Its
45+
# lean must be behaviorally compatible with the repo pin, e.g. a Lake change
46+
# cherry-picked onto the pinned release's lineage as a lean4 pr-release.
47+
# Input hashes incorporate the toolchain, so all runs safely share one
48+
# artifact scope. The analysis chain (warm-start pointer + carryover
49+
# manifests) is keyed per toolchain under analysis/<slug>/, so pinned and
50+
# override runs each warm-start from and diff against their own lineage.
51+
# A toolchain's first run — or a pr-release tag republished under the same
52+
# name — misses the legacy cache and all prior artifacts, costing one
53+
# full-turnover source build.
3454

3555
on:
3656
schedule:
@@ -54,6 +74,15 @@ on:
5474
# Mathlib.Topology.Basic Mathlib.Combinatorics.SimpleGraph.Basic Mathlib.RingTheory.Ideal.Basic
5575
# or add `Archive Counterexamples` to also shadow those libraries.
5676
default: Mathlib
77+
toolchain_override:
78+
description: >-
79+
optional Lean toolchain to run the pipeline on instead of the repo
80+
pin; see the "Toolchain override" note at the top of this file.
81+
Empty falls back to the LAKE_SHADOW_TOOLCHAIN_OVERRIDE repository
82+
variable; the pipeline runs on the repo pin when both are empty.
83+
required: false
84+
type: string
85+
default: ''
5786

5887
permissions:
5988
contents: read
@@ -67,6 +96,9 @@ defaults:
6796
shell: bash -euo pipefail {0}
6897

6998
env:
99+
# Effective toolchain override: dispatch input, else repository variable,
100+
# else the repo pin.
101+
TOOLCHAIN_OVERRIDE: ${{ inputs.toolchain_override || vars.LAKE_SHADOW_TOOLCHAIN_OVERRIDE || '' }}
70102
# Scope prefix for all puts and gets in this workflow. Namespaces the
71103
# workflow's artifacts within the cache bucket.
72104
SHADOW_SCOPE: mathlib4-master-shadow
@@ -78,7 +110,8 @@ jobs:
78110
name: Build + stage
79111
if: ${{ github.repository == 'leanprover-community/mathlib4' }}
80112
runs-on: pr
81-
timeout-minutes: 90
113+
# 240 covers the full source build of a toolchain generation's first run.
114+
timeout-minutes: ${{ (inputs.toolchain_override || vars.LAKE_SHADOW_TOOLCHAIN_OVERRIDE) && 240 || 90 }}
82115
outputs:
83116
sha: ${{ steps.resolve.outputs.sha }}
84117
toolchain: ${{ steps.resolve.outputs.toolchain }}
@@ -110,6 +143,15 @@ jobs:
110143
fetch-depth: 2
111144
path: pr-branch
112145

146+
# Before the resolve step, so the run's recorded toolchain is the one
147+
# actually used.
148+
- name: Apply toolchain override
149+
if: ${{ env.TOOLCHAIN_OVERRIDE != '' }}
150+
shell: bash -euo pipefail {0}
151+
run: |
152+
printf '%s\n' "$TOOLCHAIN_OVERRIDE" > pr-branch/lean-toolchain
153+
echo "::notice::toolchain override: $TOOLCHAIN_OVERRIDE"
154+
113155
- name: Resolve sha & toolchain
114156
id: resolve
115157
shell: bash -euo pipefail {0}
@@ -124,7 +166,10 @@ jobs:
124166
shell: bash -euo pipefail {0}
125167
run: |
126168
mkdir -p pr-branch/.lake/
127-
mkdir -p .cache/mathlib/
169+
# The landrun ruleset mounts $HOME/.cache/mathlib read-only and
170+
# errors out if the path is missing. Runs that skip legacy hydration
171+
# reach the first landrun step with it absent.
172+
mkdir -p "$HOME/.cache/mathlib/"
128173
mkdir -p _work
129174
130175
- name: install elan
@@ -135,6 +180,17 @@ jobs:
135180
./elan-init.sh -y --default-toolchain none
136181
echo "$HOME/.elan/bin" >> "${GITHUB_PATH}"
137182
183+
# `elan which` below does not auto-install non-pinned toolchains. The
184+
# uninstall forces a fresh download: pr-release tags are republished in
185+
# place, and elan skips toolchains it already has, so a persistent
186+
# runner would otherwise keep running a stale binary under that name.
187+
- name: Install override toolchain
188+
if: ${{ env.TOOLCHAIN_OVERRIDE != '' }}
189+
shell: bash -euo pipefail {0}
190+
run: |
191+
elan toolchain uninstall "$TOOLCHAIN_OVERRIDE" || true
192+
elan toolchain install "$TOOLCHAIN_OVERRIDE"
193+
138194
- name: set toolchain directory
139195
shell: bash -euo pipefail {0}
140196
run: |
@@ -168,7 +224,10 @@ jobs:
168224
cd pr-branch
169225
lake env
170226
227+
# The legacy cache is keyed to the repo's pinned toolchain — cold for an
228+
# override toolchain, where the warm-start step below takes its place.
171229
- name: Hydrate .lake/build via legacy cache
230+
if: ${{ env.TOOLCHAIN_OVERRIDE == '' }}
172231
shell: bash -euo pipefail {0}
173232
run: |
174233
cd pr-branch
@@ -199,6 +258,28 @@ jobs:
199258
awk '/^package mathlib where/,/^$/' lakefile.lean
200259
echo "::endgroup::"
201260
261+
# Seed Lake's artifact cache from the previous run on the same
262+
# toolchain, whose rev comes from that toolchain's analysis chain
263+
# (`analysis/<slug>/_latest.txt`). Only content the cache can't serve
264+
# is packed or built; a toolchain's first run has no chain yet and
265+
# proceeds from source.
266+
- name: Warm start from shadow scope
267+
shell: bash -euo pipefail {0}
268+
env:
269+
LAKE_CACHE_ARTIFACT_ENDPOINT: ${{ vars.LAKE_CACHE_ARTIFACT_ENDPOINT_PUBLIC }}
270+
LAKE_CACHE_REVISION_ENDPOINT: ${{ vars.LAKE_CACHE_REVISION_ENDPOINT_PUBLIC }}
271+
run: |
272+
# Must mirror the slug in the upload job's carryover step.
273+
slug="$(printf %s "$(cat pr-branch/lean-toolchain)" | tr -c 'A-Za-z0-9._-' '-')"
274+
prev="$(curl -fsS "${LAKE_CACHE_ARTIFACT_ENDPOINT%/artifacts}/analysis/$slug/_latest.txt" 2>/dev/null || true)"
275+
if [ -z "$prev" ]; then
276+
echo "::notice::no prior run recorded for chain $slug; proceeding without a warm start"
277+
exit 0
278+
fi
279+
cd pr-branch
280+
lake cache get --scope="$SHADOW_SCOPE" --rev="$prev" \
281+
|| echo "::warning::warm start from rev ${prev:0:12} failed; proceeding without it"
282+
202283
# Incremental build: with the legacy cache having hydrated .lake/build/
203284
# and the lakefile patched, Lake's pipeline runs to pack/cache any
204285
# modules whose .ltar+mapping aren't yet in Lake's cache. Module
@@ -277,13 +358,21 @@ jobs:
277358
LAKE_CACHE_ARTIFACT_ENDPOINT: ${{ vars.LAKE_CACHE_ARTIFACT_ENDPOINT }}
278359
LAKE_CACHE_REVISION_ENDPOINT: ${{ vars.LAKE_CACHE_REVISION_ENDPOINT }}
279360
steps:
280-
- name: Checkout mathlib (for lean-toolchain pin)
361+
- name: Checkout mathlib (workspace for put-staged)
281362
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
282363
with:
283364
ref: ${{ needs.build_and_stage.outputs.sha }}
284365
path: pr-branch
285366
fetch-depth: 1
286367

368+
# Stamp the effective toolchain from build_and_stage's resolve step, so
369+
# put-staged runs the same lake that produced the staging; the elan
370+
# proxy auto-installs it on first use.
371+
- name: Pin effective toolchain
372+
env:
373+
EFFECTIVE_TOOLCHAIN: ${{ needs.build_and_stage.outputs.toolchain }}
374+
run: printf '%s\n' "$EFFECTIVE_TOOLCHAIN" > pr-branch/lean-toolchain
375+
287376
- name: install elan + matching lake
288377
run: |
289378
curl -o elan-init.sh -sSfL https://elan.lean-lang.org/elan-init.sh
@@ -318,7 +407,8 @@ jobs:
318407
--toolchain="${{ needs.build_and_stage.outputs.toolchain }}" 2>&1 | tee /tmp/put.log
319408
320409
# Cache carryover analysis: diff this run's uploaded artifact set against
321-
# the previous run's, using a tiny per-run manifest kept in the bucket.
410+
# the previous run's on the same toolchain, via tiny per-run manifests
411+
# kept in the bucket under the toolchain's analysis/<slug>/ prefix.
322412
# Here:
323413
# carryover = artifacts also present last run;
324414
# new = this run's churn (≈ how much Mathlib changed since the last build).
@@ -331,8 +421,11 @@ jobs:
331421
AUTH: ${{ vars.LAKE_CACHE_ARTIFACT_ENDPOINT }}
332422
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
333423
REPO: ${{ github.repository }}
424+
EFFECTIVE_TOOLCHAIN: ${{ needs.build_and_stage.outputs.toolchain }}
334425
run: |
335-
base="${AUTH%/artifacts}/analysis"
426+
# Must mirror the slug in build_and_stage's warm-start step.
427+
slug="$(printf %s "$EFFECTIVE_TOOLCHAIN" | tr -c 'A-Za-z0-9._-' '-')"
428+
base="${AUTH%/artifacts}/analysis/$slug"
336429
sha="${{ needs.build_and_stage.outputs.sha }}"
337430
sig=(--aws-sigv4 aws:amz:auto:s3 --user "$LAKE_CACHE_KEY")
338431
# grep exits 1 on no match (handled by the total==0 branch); tolerate it under pipefail.
@@ -379,7 +472,7 @@ jobs:
379472
new_content="$(numfmt --to=iec-i --suffix=B "$new_bytes") across ${new} new artifact(s) vs rev ${prev:0:12}${distnote}"
380473
pct=$(awk "BEGIN{printf \"%.1f\", ($total>0)?100*$carry/$total:0}")
381474
note=""
382-
[ "$total" -gt 0 ] && [ "$new" -eq "$total" ] && note=" — full turnover, likely a toolchain/generation change, not source churn"
475+
[ "$total" -gt 0 ] && [ "$new" -eq "$total" ] && note=" — full turnover, likely a republished toolchain binary, not source churn"
383476
summary="${carry}/${total} (${pct}%) carried over, ${new} new vs rev ${prev:0:12}${note}"
384477
fi
385478
echo "::notice::cache carryover: ${summary}"
@@ -396,7 +489,7 @@ jobs:
396489
needs: [build_and_stage, upload]
397490
if: ${{ github.repository == 'leanprover-community/mathlib4' }}
398491
runs-on: ubuntu-latest
399-
timeout-minutes: 60
492+
timeout-minutes: 90
400493
outputs:
401494
cache_health: ${{ steps.cachehealth.outputs.health }}
402495
env:
@@ -416,6 +509,14 @@ jobs:
416509
path: pr-branch
417510
fetch-depth: 1
418511

512+
# Stamp the effective toolchain from build_and_stage's resolve step, so
513+
# the replay runs the same lake that built the artifacts; the elan
514+
# proxy auto-installs it on first use.
515+
- name: Pin effective toolchain
516+
env:
517+
EFFECTIVE_TOOLCHAIN: ${{ needs.build_and_stage.outputs.toolchain }}
518+
run: printf '%s\n' "$EFFECTIVE_TOOLCHAIN" > pr-branch/lean-toolchain
519+
419520
- name: install elan
420521
run: |
421522
curl -o elan-init.sh -sSfL https://elan.lean-lang.org/elan-init.sh
@@ -533,6 +634,9 @@ jobs:
533634
{
534635
echo "msg<<MSG_EOF"
535636
echo "**Lake cache shadow** ([run](${RUN_URL}), rev \`${SHA:0:12}\`)"
637+
if [ -n "${TOOLCHAIN_OVERRIDE:-}" ]; then
638+
echo "🧪 toolchain override: \`${TOOLCHAIN_OVERRIDE}\`"
639+
fi
536640
echo ""
537641
echo "- $(emoji "$BUILD") build_and_stage: \`$BUILD\`"
538642
echo "- $(emoji "$UPLOAD") upload: \`$UPLOAD\`"
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Periodic safety net that keeps the Zulip emoji reactions on PR-related messages
2+
# in sync with each PR's actual state (open/closed/merged, labels, CI result).
3+
# The event-driven zulip_emoji_* workflows react to individual label/close/CI
4+
# events; this sweep repairs any drift they miss (dropped webhooks, outages,
5+
# state changes while a workflow was broken). See
6+
# https://github.com/leanprover-community/mathlib-ci/blob/master/docs/zulip-emoji-reconcile.md
7+
name: Zulip emoji reconcile
8+
9+
on:
10+
schedule:
11+
- cron: "37 * * * *" # hourly, offset to dodge top-of-hour runner load
12+
workflow_dispatch:
13+
inputs:
14+
dry-run:
15+
description: Log planned reaction changes without modifying Zulip
16+
type: boolean
17+
default: false
18+
19+
concurrency:
20+
group: ${{ github.workflow }}
21+
cancel-in-progress: false
22+
23+
permissions:
24+
contents: read
25+
pull-requests: read
26+
27+
jobs:
28+
reconcile:
29+
if: github.repository == 'leanprover-community/mathlib4'
30+
runs-on: ubuntu-latest
31+
steps:
32+
- name: Check out reconcile config
33+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
34+
with:
35+
sparse-checkout: .github/zulip-emoji-config.json
36+
sparse-checkout-cone-mode: false
37+
38+
- name: Reconcile
39+
uses: leanprover-community/mathlib-ci/.github/actions/zulip-emoji-reconcile@5668fbbccf0fecefdfcddf539b8406db197dfc59
40+
with:
41+
config: .github/zulip-emoji-config.json
42+
sweep: true
43+
dry-run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry-run }}
44+
zulip-api-key: ${{ secrets.ZULIP_API_KEY }}
45+
github-token: ${{ github.token }}

.github/zulip-emoji-config.json

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
{
2+
"_comment": "Config for the zulip-emoji-reconcile action (see .github/workflows/zulip_emoji_reconcile.yml), which keeps Zulip emoji reactions in sync with PR state. Format and semantics: https://github.com/leanprover-community/mathlib-ci/blob/master/docs/zulip-emoji-reconcile.md. Derived from scripts/zulip/examples/mathlib4-config.json in that repo; keep the two in sync when the emoji table changes.",
3+
4+
"github_repo": "leanprover-community/mathlib4",
5+
6+
"_merged_comment": "bors merges by rebasing a PR's commits onto master, so GitHub reports the PR as CLOSED (not merged) and renames its title to start with '[Merged by Bors] -'. Treat such closed PRs as merged so they get the 'merge' emoji rather than 'closed-pr'. Drop this key for repos that merge via the GitHub merge button/queue, where the PR state is reported as MERGED directly.",
7+
"merged_title_prefix": "[Merged by Bors] -",
8+
9+
"zulip": {
10+
"site": "https://leanprover.zulipchat.com",
11+
"email": "github-mathlib4-bot@leanprover.zulipchat.com"
12+
},
13+
14+
"channels": {
15+
"pr_reviews": "PR reviews",
16+
"reviewers": "mathlib reviewers",
17+
"rss_allow": ["mathlib bors notifications"]
18+
},
19+
20+
"ci": {
21+
"_comment": "Case-insensitive substring match against check-run name, workflow name, or status context. The first three select the gating jobs of 'continuous integration' / 'continuous integration (mathlib forks)' -- their check runs are named 'ci / Build', 'ci (fork) / Build', etc. -- while leaving auxiliary jobs (Upload to cache, Post-CI job) out of the emoji. 'Check workflows' is the actionlint workflow: it runs only on PRs touching .github/**, so it contributes nothing on ordinary PRs and becomes the CI signal on workflows-only PRs where the main CI never triggers.",
22+
"check_names": ["Build", "Lint style", "Post-Build Step", "Check workflows"]
23+
},
24+
25+
"states": [
26+
{
27+
"name": "merged", "group": "pr", "priority": 30,
28+
"source": {"state": "merged"}, "emoji": "merge"
29+
},
30+
{
31+
"name": "closed", "group": "pr", "priority": 20,
32+
"source": {"state": "closed"},
33+
"emoji": "closed-pr", "emoji_code": "61293", "reaction_type": "realm_emoji"
34+
},
35+
{
36+
"name": "ready-to-merge", "group": "pr", "priority": 12,
37+
"source": {"label": "ready-to-merge"},
38+
"emoji": "bors", "emoji_code": "22134", "reaction_type": "realm_emoji"
39+
},
40+
{
41+
"name": "delegated", "group": "pr", "priority": 11,
42+
"source": {"label": "delegated"}, "emoji": "peace_sign"
43+
},
44+
{
45+
"name": "awaiting-author", "group": "pr", "priority": 10,
46+
"source": {"label": "awaiting-author"}, "emoji": "writing"
47+
},
48+
49+
{"name": "ci-running", "group": "ci", "source": {"ci": "running"}, "emoji": "yellow"},
50+
{"name": "ci-success", "group": "ci", "source": {"ci": "success"}, "emoji": "check"},
51+
{"name": "ci-failure", "group": "ci", "source": {"ci": "failure"}, "emoji": "cross_mark"},
52+
53+
{
54+
"name": "maintainer-merge", "group": null,
55+
"source": {"label": "maintainer-merge"}, "emoji": "hammer",
56+
"suppress_in": {"channel": "reviewers", "subject_prefix": "maintainer merge"}
57+
},
58+
{
59+
"name": "migrated", "group": null, "sticky": true,
60+
"source": {"label": "migrated-from-branch"}, "emoji": "skip_forward"
61+
}
62+
]
63+
}

Archive/Examples/Kuratowski.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ theorem nodup_theFourteen_fourteenSet : (theFourteen fourteenSet).Nodup :=
253253

254254
/-- The number of distinct sets obtainable from `fourteenSet` is exactly 14. -/
255255
theorem ncard_isObtainable_fourteenSet : {t | IsObtainable fourteenSet t}.ncard = 14 := by
256-
classical rw [← card_theFourteen fourteenSet, ← Multiset.toFinset_card_of_nodup
256+
rw [← card_theFourteen fourteenSet, ← Multiset.toFinset_card_of_nodup
257257
nodup_theFourteen_fourteenSet, ← Set.ncard_coe_finset]
258258
congr; ext; simp [mem_theFourteen_iff_isObtainable]
259259

Archive/Hairer.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ def L : MvPolynomial ι ℝ →ₗ[ℝ]
9393
(fun p f₁ f₂ ↦ by simp_rw [smul_eq_mul, ← integral_add (int p _) (int p _), ← mul_add]; rfl)
9494
fun r p f ↦ by simp_rw [← integral_smul, smul_comm r]; rfl
9595

96+
set_option backward.isDefEq.respectTransparency.types false in
9697
lemma inj_L : Injective (L ι) :=
9798
(injective_iff_map_eq_zero _).mpr fun p hp ↦ by
9899
have H : ∀ᵐ x : EuclideanSpace ℝ ι, x ∈ ball 0 1 → eval x p = 0 :=

0 commit comments

Comments
 (0)