ZAIDX11 commited on
Commit
19faf57
·
verified ·
1 Parent(s): 7146f6f

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +10 -0
  2. MyProject/.lake/build/bin/myproject.exe +3 -0
  3. MyProject/.lake/build/ir/Main.c.o.noexport.hash +1 -0
  4. MyProject/.lake/build/ir/Main.c.o.noexport.trace +17 -0
  5. MyProject/.lake/build/ir/Main.setup.json +6 -0
  6. MyProject/.lake/build/ir/MyProject.c +33 -0
  7. MyProject/.lake/build/ir/MyProject.c.hash +1 -0
  8. MyProject/.lake/build/ir/MyProject.c.o.noexport +0 -0
  9. MyProject/.lake/build/ir/MyProject.c.o.noexport.hash +1 -0
  10. MyProject/.lake/build/ir/MyProject.c.o.noexport.trace +17 -0
  11. MyProject/.lake/build/ir/MyProject.setup.json +6 -0
  12. MyProject/.lake/build/ir/MyProject/Basic.c +51 -0
  13. MyProject/.lake/build/ir/MyProject/Basic.c.hash +1 -0
  14. MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport +0 -0
  15. MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport.hash +1 -0
  16. MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport.trace +17 -0
  17. MyProject/.lake/build/ir/MyProject/Basic.setup.json +6 -0
  18. MyProject/.lake/build/lib/lean/Main.ilean +1 -0
  19. MyProject/.lake/build/lib/lean/Main.ilean.hash +1 -0
  20. MyProject/.lake/build/lib/lean/Main.olean +0 -0
  21. MyProject/.lake/build/lib/lean/Main.olean.hash +1 -0
  22. MyProject/.lake/build/lib/lean/Main.trace +30 -0
  23. MyProject/.lake/build/lib/lean/MyProject.ilean +1 -0
  24. MyProject/.lake/build/lib/lean/MyProject.ilean.hash +1 -0
  25. MyProject/.lake/build/lib/lean/MyProject.olean +0 -0
  26. MyProject/.lake/build/lib/lean/MyProject.olean.hash +1 -0
  27. MyProject/.lake/build/lib/lean/MyProject.trace +30 -0
  28. MyProject/.lake/build/lib/lean/MyProject/Basic.ilean +1 -0
  29. MyProject/.lake/build/lib/lean/MyProject/Basic.ilean.hash +1 -0
  30. MyProject/.lake/build/lib/lean/MyProject/Basic.olean +0 -0
  31. MyProject/.lake/build/lib/lean/MyProject/Basic.olean.hash +1 -0
  32. MyProject/.lake/build/lib/lean/MyProject/Basic.trace +26 -0
  33. MyProject/MyProject/Basic.lean +1 -0
  34. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Nonrec/Eqns.lean +56 -0
  35. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Eqns.lean +124 -0
  36. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Induction.lean +402 -0
  37. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Main.lean +224 -0
  38. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/BRecOn.lean +293 -0
  39. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Basic.lean +103 -0
  40. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Eqns.lean +155 -0
  41. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/FindRecArg.lean +281 -0
  42. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/IndGroupInfo.lean +109 -0
  43. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/IndPred.lean +137 -0
  44. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Main.lean +209 -0
  45. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Preprocess.lean +53 -0
  46. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/RecArgInfo.lean +70 -0
  47. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/SmartUnfolding.lean +71 -0
  48. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/WF/Basic.lean +25 -0
  49. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/WF/Eqns.lean +82 -0
  50. backend/core/leanprover--lean4---v4.22.0/src/lean/Std/Data/HashMap/Lemmas.lean +0 -0
.gitattributes CHANGED
@@ -4493,3 +4493,13 @@ backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Internal/Parsec/ByteArray.
4493
  backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Data/TreeSet/Basic.olean filter=lfs diff=lfs merge=lfs -text
4494
  backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Data/Iterators/Lemmas/Combinators/TakeWhile.olean filter=lfs diff=lfs merge=lfs -text
4495
  external/alphageometry/.venv-ag/Lib/site-packages/scipy/special/tests/data/local.npz filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
4493
  backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Data/TreeSet/Basic.olean filter=lfs diff=lfs merge=lfs -text
4494
  backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Data/Iterators/Lemmas/Combinators/TakeWhile.olean filter=lfs diff=lfs merge=lfs -text
4495
  external/alphageometry/.venv-ag/Lib/site-packages/scipy/special/tests/data/local.npz filter=lfs diff=lfs merge=lfs -text
4496
+ external/alphageometry/.venv-ag/Lib/site-packages/scipy/linalg/tests/data/carex_18_data.npz filter=lfs diff=lfs merge=lfs -text
4497
+ hfenv/Scripts/python.exe filter=lfs diff=lfs merge=lfs -text
4498
+ hfenv/Scripts/pythonw.exe filter=lfs diff=lfs merge=lfs -text
4499
+ MyProject/.lake/build/bin/myproject.exe filter=lfs diff=lfs merge=lfs -text
4500
+ external/alphageometry/.venv-ag/Lib/site-packages/scipy/stats/tests/data/levy_stable/stable-Z1-pdf-sample-data.npy filter=lfs diff=lfs merge=lfs -text
4501
+ external/alphageometry/.venv-ag/Lib/site-packages/numpy/random/lib/npyrandom.lib filter=lfs diff=lfs merge=lfs -text
4502
+ external/alphageometry/.venv-ag/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans-BoldOblique.ttf filter=lfs diff=lfs merge=lfs -text
4503
+ external/alphageometry/.venv-ag/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf filter=lfs diff=lfs merge=lfs -text
4504
+ external/alphageometry/.venv-ag/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Bold.ttf filter=lfs diff=lfs merge=lfs -text
4505
+ external/alphageometry/.venv-ag/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-BoldOblique.ttf filter=lfs diff=lfs merge=lfs -text
MyProject/.lake/build/bin/myproject.exe ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:600f5a03635f9f4e2411d2073f2a9b082a0894af45fbfd6eb440074bba0eab51
3
+ size 8729600
MyProject/.lake/build/ir/Main.c.o.noexport.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 6845279270828235154
MyProject/.lake/build/ir/Main.c.o.noexport.trace ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"synthetic": false,
2
+ "outputs": "6845279270828235154",
3
+ "log":
4
+ [{"message":
5
+ ".> c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\bin\\clang.exe -c -o C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\Main.c.o.noexport C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\Main.c -I c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\include -fstack-clash-protection -fwrapv -Wno-unused-command-line-argument --sysroot c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0 -nostdinc -isystem c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0/include/clang -O3 -DNDEBUG",
6
+ "level": "trace"}],
7
+ "inputs":
8
+ [["Main:c",
9
+ [["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\Main.c",
10
+ "2812497700029973126"],
11
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
12
+ "8739116525927611134"]]],
13
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
14
+ "8739116525927611134"],
15
+ ["traceArgs: #[-O3, -DNDEBUG]", "7817036117363455818"],
16
+ ["x86_64-w64-windows-gnu", "3894966287860160785"]],
17
+ "depHash": "13981209688990805943"}
MyProject/.lake/build/ir/Main.setup.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {"plugins": [],
2
+ "options": {},
3
+ "name": "Main",
4
+ "isModule": false,
5
+ "importArts": {},
6
+ "dynlibs": []}
MyProject/.lake/build/ir/MyProject.c ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Lean compiler output
2
+ // Module: MyProject
3
+ // Imports: Init MyProject.Basic
4
+ #include <lean/lean.h>
5
+ #if defined(__clang__)
6
+ #pragma clang diagnostic ignored "-Wunused-parameter"
7
+ #pragma clang diagnostic ignored "-Wunused-label"
8
+ #elif defined(__GNUC__) && !defined(__CLANG__)
9
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
10
+ #pragma GCC diagnostic ignored "-Wunused-label"
11
+ #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
12
+ #endif
13
+ #ifdef __cplusplus
14
+ extern "C" {
15
+ #endif
16
+ lean_object* initialize_Init(uint8_t builtin, lean_object*);
17
+ lean_object* initialize_MyProject_Basic(uint8_t builtin, lean_object*);
18
+ static bool _G_initialized = false;
19
+ LEAN_EXPORT lean_object* initialize_MyProject(uint8_t builtin, lean_object* w) {
20
+ lean_object * res;
21
+ if (_G_initialized) return lean_io_result_mk_ok(lean_box(0));
22
+ _G_initialized = true;
23
+ res = initialize_Init(builtin, lean_io_mk_world());
24
+ if (lean_io_result_is_error(res)) return res;
25
+ lean_dec_ref(res);
26
+ res = initialize_MyProject_Basic(builtin, lean_io_mk_world());
27
+ if (lean_io_result_is_error(res)) return res;
28
+ lean_dec_ref(res);
29
+ return lean_io_result_mk_ok(lean_box(0));
30
+ }
31
+ #ifdef __cplusplus
32
+ }
33
+ #endif
MyProject/.lake/build/ir/MyProject.c.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 10253638930955786439
MyProject/.lake/build/ir/MyProject.c.o.noexport ADDED
Binary file (1.21 kB). View file
 
MyProject/.lake/build/ir/MyProject.c.o.noexport.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 1337897845214833469
MyProject/.lake/build/ir/MyProject.c.o.noexport.trace ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"synthetic": false,
2
+ "outputs": "1337897845214833469",
3
+ "log":
4
+ [{"message":
5
+ ".> c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\bin\\clang.exe -c -o C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject.c.o.noexport C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject.c -I c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\include -fstack-clash-protection -fwrapv -Wno-unused-command-line-argument --sysroot c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0 -nostdinc -isystem c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0/include/clang -O3 -DNDEBUG",
6
+ "level": "trace"}],
7
+ "inputs":
8
+ [["MyProject:c",
9
+ [["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject.c",
10
+ "10253638930955786439"],
11
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
12
+ "8739116525927611134"]]],
13
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
14
+ "8739116525927611134"],
15
+ ["traceArgs: #[-O3, -DNDEBUG]", "7817036117363455818"],
16
+ ["x86_64-w64-windows-gnu", "3894966287860160785"]],
17
+ "depHash": "6185683997854951944"}
MyProject/.lake/build/ir/MyProject.setup.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {"plugins": [],
2
+ "options": {},
3
+ "name": "MyProject",
4
+ "isModule": false,
5
+ "importArts": {},
6
+ "dynlibs": []}
MyProject/.lake/build/ir/MyProject/Basic.c ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Lean compiler output
2
+ // Module: MyProject.Basic
3
+ // Imports: Init
4
+ #include <lean/lean.h>
5
+ #if defined(__clang__)
6
+ #pragma clang diagnostic ignored "-Wunused-parameter"
7
+ #pragma clang diagnostic ignored "-Wunused-label"
8
+ #elif defined(__GNUC__) && !defined(__CLANG__)
9
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
10
+ #pragma GCC diagnostic ignored "-Wunused-label"
11
+ #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
12
+ #endif
13
+ #ifdef __cplusplus
14
+ extern "C" {
15
+ #endif
16
+ LEAN_EXPORT lean_object* l_hello;
17
+ static lean_object* l_hello___closed__0;
18
+ static lean_object* _init_l_hello___closed__0() {
19
+ _start:
20
+ {
21
+ lean_object* x_1;
22
+ x_1 = lean_mk_string_unchecked("world", 5, 5);
23
+ return x_1;
24
+ }
25
+ }
26
+ static lean_object* _init_l_hello() {
27
+ _start:
28
+ {
29
+ lean_object* x_1;
30
+ x_1 = l_hello___closed__0;
31
+ return x_1;
32
+ }
33
+ }
34
+ lean_object* initialize_Init(uint8_t builtin, lean_object*);
35
+ static bool _G_initialized = false;
36
+ LEAN_EXPORT lean_object* initialize_MyProject_Basic(uint8_t builtin, lean_object* w) {
37
+ lean_object * res;
38
+ if (_G_initialized) return lean_io_result_mk_ok(lean_box(0));
39
+ _G_initialized = true;
40
+ res = initialize_Init(builtin, lean_io_mk_world());
41
+ if (lean_io_result_is_error(res)) return res;
42
+ lean_dec_ref(res);
43
+ l_hello___closed__0 = _init_l_hello___closed__0();
44
+ lean_mark_persistent(l_hello___closed__0);
45
+ l_hello = _init_l_hello();
46
+ lean_mark_persistent(l_hello);
47
+ return lean_io_result_mk_ok(lean_box(0));
48
+ }
49
+ #ifdef __cplusplus
50
+ }
51
+ #endif
MyProject/.lake/build/ir/MyProject/Basic.c.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 6640969564603399067
MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport ADDED
Binary file (1.42 kB). View file
 
MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 535684011917836214
MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport.trace ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"synthetic": false,
2
+ "outputs": "535684011917836214",
3
+ "log":
4
+ [{"message":
5
+ ".> c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\bin\\clang.exe -c -o C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject\\Basic.c.o.noexport C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject\\Basic.c -I c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\include -fstack-clash-protection -fwrapv -Wno-unused-command-line-argument --sysroot c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0 -nostdinc -isystem c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0/include/clang -O3 -DNDEBUG",
6
+ "level": "trace"}],
7
+ "inputs":
8
+ [["MyProject.Basic:c",
9
+ [["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject\\Basic.c",
10
+ "6640969564603399067"],
11
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
12
+ "8739116525927611134"]]],
13
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
14
+ "8739116525927611134"],
15
+ ["traceArgs: #[-O3, -DNDEBUG]", "7817036117363455818"],
16
+ ["x86_64-w64-windows-gnu", "3894966287860160785"]],
17
+ "depHash": "16832078366333324937"}
MyProject/.lake/build/ir/MyProject/Basic.setup.json ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ {"plugins": [],
2
+ "options": {},
3
+ "name": "MyProject.Basic",
4
+ "isModule": false,
5
+ "importArts": {},
6
+ "dynlibs": []}
MyProject/.lake/build/lib/lean/Main.ilean ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":4,"references":{"{\"c\":{\"n\":\"main\",\"m\":\"Main\"}}":{"usages":[],"definition":[2,4,2,8]},"{\"c\":{\"n\":\"hello\",\"m\":\"MyProject.Basic\"}}":{"usages":[[3,24,3,29,"main",2,0,3,32,2,4,2,8]],"definition":null},"{\"c\":{\"n\":\"Unit\",\"m\":\"Init.Prelude\"}}":{"usages":[[2,14,2,18,"main",2,0,3,32,2,4,2,8]],"definition":null},"{\"c\":{\"n\":\"IO.println\",\"m\":\"Init.System.IO\"}}":{"usages":[[3,2,3,12,"main",2,0,3,32,2,4,2,8]],"definition":null},"{\"c\":{\"n\":\"IO\",\"m\":\"Init.System.IO\"}}":{"usages":[[2,11,2,13,"main",2,0,3,32,2,4,2,8]],"definition":null}},"module":"Main","directImports":[["MyProject",false,false,false]]}
MyProject/.lake/build/lib/lean/Main.ilean.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 7502200330849018073
MyProject/.lake/build/lib/lean/Main.olean ADDED
Binary file (33.3 kB). View file
 
MyProject/.lake/build/lib/lean/Main.olean.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 16614596214648291283
MyProject/.lake/build/lib/lean/Main.trace ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"synthetic": false,
2
+ "outputs":
3
+ {"o": ["16614596214648291283"],
4
+ "i": "7502200330849018073",
5
+ "c": "2812497700029973126"},
6
+ "log":
7
+ [{"message":
8
+ ".> LEAN_PATH=C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\bin\\lean.exe C:\\Users\\marooc\\AXIOVORA X\\MyProject\\Main.lean -o C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\Main.olean -i C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\Main.ilean -c C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\Main.c --setup C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\Main.setup.json --json",
9
+ "level": "trace"}],
10
+ "inputs":
11
+ [["Main:deps",
12
+ [["deps",
13
+ [["MyProject/myproject:extraDep", [["@MyProject:extraDep", "1723"]]],
14
+ ["import oleans",
15
+ [["MyProject:olean",
16
+ [["MyProject:deps", "8480390225429029242"],
17
+ ["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\MyProject.olean",
18
+ "2826512291163496019"]]]]]]],
19
+ ["libs",
20
+ [["import dynlibs", "1723"],
21
+ ["package external libraries", "1723"],
22
+ ["module dynlibs", "1723"],
23
+ ["module plugins", "1723"]]]]],
24
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
25
+ "8739116525927611134"],
26
+ ["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\Main.lean",
27
+ "16909483731186443744"],
28
+ ["options", "1723"],
29
+ ["Module.leanArgs: #[]", "1723"]],
30
+ "depHash": "11749844063866404310"}
MyProject/.lake/build/lib/lean/MyProject.ilean ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":4,"references":{},"module":"MyProject","directImports":[["MyProject.Basic",false,false,false]]}
MyProject/.lake/build/lib/lean/MyProject.ilean.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 1223145565319205264
MyProject/.lake/build/lib/lean/MyProject.olean ADDED
Binary file (18.8 kB). View file
 
MyProject/.lake/build/lib/lean/MyProject.olean.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 2826512291163496019
MyProject/.lake/build/lib/lean/MyProject.trace ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"synthetic": false,
2
+ "outputs":
3
+ {"o": ["2826512291163496019"],
4
+ "i": "1223145565319205264",
5
+ "c": "10253638930955786439"},
6
+ "log":
7
+ [{"message":
8
+ ".> LEAN_PATH=C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\bin\\lean.exe C:\\Users\\marooc\\AXIOVORA X\\MyProject\\MyProject.lean -o C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\MyProject.olean -i C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\MyProject.ilean -c C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject.c --setup C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject.setup.json --json",
9
+ "level": "trace"}],
10
+ "inputs":
11
+ [["MyProject:deps",
12
+ [["deps",
13
+ [["MyProject/MyProject:extraDep", [["@MyProject:extraDep", "1723"]]],
14
+ ["import oleans",
15
+ [["MyProject.Basic:olean",
16
+ [["MyProject.Basic:deps", "12720339749678921893"],
17
+ ["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\MyProject\\Basic.olean",
18
+ "6875692082518850885"]]]]]]],
19
+ ["libs",
20
+ [["import dynlibs", "1723"],
21
+ ["package external libraries", "1723"],
22
+ ["module dynlibs", "1723"],
23
+ ["module plugins", "1723"]]]]],
24
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
25
+ "8739116525927611134"],
26
+ ["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\MyProject.lean",
27
+ "12336320995415267534"],
28
+ ["options", "1723"],
29
+ ["Module.leanArgs: #[]", "1723"]],
30
+ "depHash": "5093461821927556036"}
MyProject/.lake/build/lib/lean/MyProject/Basic.ilean ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":4,"references":{"{\"c\":{\"n\":\"hello\",\"m\":\"MyProject.Basic\"}}":{"usages":[],"definition":[0,4,0,9]}},"module":"MyProject.Basic","directImports":[]}
MyProject/.lake/build/lib/lean/MyProject/Basic.ilean.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 16625990806461164587
MyProject/.lake/build/lib/lean/MyProject/Basic.olean ADDED
Binary file (20.6 kB). View file
 
MyProject/.lake/build/lib/lean/MyProject/Basic.olean.hash ADDED
@@ -0,0 +1 @@
 
 
1
+ 6875692082518850885
MyProject/.lake/build/lib/lean/MyProject/Basic.trace ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {"synthetic": false,
2
+ "outputs":
3
+ {"o": ["6875692082518850885"],
4
+ "i": "16625990806461164587",
5
+ "c": "6640969564603399067"},
6
+ "log":
7
+ [{"message":
8
+ ".> LEAN_PATH=C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean c:\\Users\\marooc\\.elan\\toolchains\\leanprover--lean4---v4.22.0\\bin\\lean.exe C:\\Users\\marooc\\AXIOVORA X\\MyProject\\MyProject\\Basic.lean -o C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\MyProject\\Basic.olean -i C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\lib\\lean\\MyProject\\Basic.ilean -c C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject\\Basic.c --setup C:\\Users\\marooc\\AXIOVORA X\\MyProject\\.lake\\build\\ir\\MyProject\\Basic.setup.json --json",
9
+ "level": "trace"}],
10
+ "inputs":
11
+ [["MyProject.Basic:deps",
12
+ [["deps",
13
+ [["MyProject/MyProject:extraDep", [["@MyProject:extraDep", "1723"]]],
14
+ ["import oleans", "1723"]]],
15
+ ["libs",
16
+ [["import dynlibs", "1723"],
17
+ ["package external libraries", "1723"],
18
+ ["module dynlibs", "1723"],
19
+ ["module plugins", "1723"]]]]],
20
+ ["Lean 4.22.0, commit ba2cbbf09d4978f416e0ebd1fceeebc2c4138c05",
21
+ "8739116525927611134"],
22
+ ["C:\\Users\\marooc\\AXIOVORA X\\MyProject\\MyProject\\Basic.lean",
23
+ "18126205365334327008"],
24
+ ["options", "1723"],
25
+ ["Module.leanArgs: #[]", "1723"]],
26
+ "depHash": "16222576468637617417"}
MyProject/MyProject/Basic.lean ADDED
@@ -0,0 +1 @@
 
 
1
+ def hello := "world"
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Nonrec/Eqns.lean ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Tactic.Rewrite
8
+ import Lean.Meta.Tactic.Split
9
+ import Lean.Elab.PreDefinition.Basic
10
+ import Lean.Elab.PreDefinition.Eqns
11
+ import Lean.Meta.ArgsPacker.Basic
12
+ import Init.Data.Array.Basic
13
+
14
+ namespace Lean.Elab.Nonrec
15
+ open Meta
16
+ open Eqns
17
+
18
+ /--
19
+ Simple, coarse-grained equation theorem for nonrecursive definitions.
20
+ -/
21
+ private def mkSimpleEqThm (declName : Name) : MetaM (Option Name) := do
22
+ if let some (.defnInfo info) := (← getEnv).find? declName then
23
+ let name := mkEqLikeNameFor (← getEnv) declName eqn1ThmSuffix
24
+ trace[Elab.definition.eqns] "mkSimpleEqnThm: {name}"
25
+ realizeConst declName name (doRealize name info)
26
+ return some name
27
+ else
28
+ return none
29
+ where
30
+ doRealize name info :=
31
+ lambdaTelescope (cleanupAnnotations := true) info.value fun xs body => do
32
+ let lhs := mkAppN (mkConst info.name <| info.levelParams.map mkLevelParam) xs
33
+ let type ← mkForallFVars xs (← mkEq lhs body)
34
+ let value ← mkLambdaFVars xs (← mkEqRefl lhs)
35
+ addDecl <| .thmDecl {
36
+ name, type, value
37
+ levelParams := info.levelParams
38
+ }
39
+ inferDefEqAttr name
40
+
41
+ def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
42
+ if (← isRecursiveDefinition declName) then
43
+ return none
44
+ if (← getEnv).contains declName then
45
+ if backward.eqns.nonrecursive.get (← getOptions) then
46
+ mkEqns declName #[]
47
+ else
48
+ let o ← mkSimpleEqThm declName
49
+ return o.map (#[·])
50
+ else
51
+ return none
52
+
53
+ builtin_initialize
54
+ registerGetEqnsFn getEqnsFor?
55
+
56
+ end Lean.Elab.Nonrec
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Eqns.lean ADDED
@@ -0,0 +1,124 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Tactic.Conv
8
+ import Lean.Meta.Tactic.Rewrite
9
+ import Lean.Meta.Tactic.Split
10
+ import Lean.Elab.PreDefinition.Basic
11
+ import Lean.Elab.PreDefinition.Eqns
12
+ import Lean.Elab.PreDefinition.FixedParams
13
+ import Lean.Meta.ArgsPacker.Basic
14
+ import Init.Data.Array.Basic
15
+ import Init.Internal.Order.Basic
16
+
17
+ namespace Lean.Elab.PartialFixpoint
18
+ open Meta
19
+ open Eqns
20
+
21
+ structure EqnInfo extends EqnInfoCore where
22
+ declNames : Array Name
23
+ declNameNonRec : Name
24
+ fixedParamPerms : FixedParamPerms
25
+ fixpointType : Array PartialFixpointType
26
+ deriving Inhabited
27
+
28
+ builtin_initialize eqnInfoExt : MapDeclarationExtension EqnInfo ← mkMapDeclarationExtension
29
+
30
+ def registerEqnsInfo (preDefs : Array PreDefinition) (declNameNonRec : Name)
31
+ (fixedParamPerms : FixedParamPerms) (fixpointType : Array PartialFixpointType): MetaM Unit := do
32
+ preDefs.forM fun preDef => ensureEqnReservedNamesAvailable preDef.declName
33
+ unless preDefs.all fun p => p.kind.isTheorem do
34
+ unless (← preDefs.allM fun p => isProp p.type) do
35
+ let declNames := preDefs.map (·.declName)
36
+ modifyEnv fun env =>
37
+ preDefs.foldl (init := env) fun env preDef =>
38
+ eqnInfoExt.insert env preDef.declName { preDef with
39
+ declNames, declNameNonRec, fixedParamPerms, fixpointType }
40
+
41
+ private def deltaLHSUntilFix (declName declNameNonRec : Name) (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
42
+ let target ← mvarId.getType'
43
+ let some (_, lhs, rhs) := target.eq? | throwTacticEx `deltaLHSUntilFix mvarId "equality expected"
44
+ let lhs' ← deltaExpand lhs fun n => n == declName || n == declNameNonRec
45
+ mvarId.replaceTargetDefEq (← mkEq lhs' rhs)
46
+
47
+ partial def rwFixUnder (lhs : Expr) : MetaM Expr := do
48
+ if lhs.isAppOfArity ``Order.fix 4 then
49
+ return mkAppN (mkConst ``Order.fix_eq lhs.getAppFn.constLevels!) lhs.getAppArgs
50
+ else if lhs.isAppOfArity ``Order.lfp_monotone 4 then
51
+ return mkAppN (mkConst ``Order.lfp_monotone_fix lhs.getAppFn.constLevels!) lhs.getAppArgs
52
+ else if lhs.isApp then
53
+ let h ← rwFixUnder lhs.appFn!
54
+ mkAppM ``congrFun #[h, lhs.appArg!]
55
+ else if lhs.isProj then
56
+ let f := mkLambda `p .default (← inferType lhs.projExpr!) (lhs.updateProj! (.bvar 0))
57
+ let h ← rwFixUnder lhs.projExpr!
58
+ mkAppM ``congrArg #[f, h]
59
+ else
60
+ throwError "rwFixUnder: unexpected expression {lhs}"
61
+
62
+ private def rwFixEq (mvarId : MVarId) : MetaM MVarId := mvarId.withContext do
63
+ let mut mvarId := mvarId
64
+ let target ← mvarId.getType'
65
+ let some (_, lhs, rhs) := target.eq? | unreachable!
66
+ let h ← rwFixUnder lhs
67
+ let some (_, _, lhsNew) := (← inferType h).eq? | unreachable!
68
+ let targetNew ← mkEq lhsNew rhs
69
+ let mvarNew ← mkFreshExprSyntheticOpaqueMVar targetNew
70
+ mvarId.assign (← mkEqTrans h mvarNew)
71
+ return mvarNew.mvarId!
72
+
73
+ /-- Generate the "unfold" lemma for `declName`. -/
74
+ def mkUnfoldEq (declName : Name) (info : EqnInfo) : MetaM Name := do
75
+ let name := mkEqLikeNameFor (← getEnv) declName unfoldThmSuffix
76
+ realizeConst declName name (doRealize name)
77
+ return name
78
+ where
79
+ doRealize name := withOptions (tactic.hygienic.set · false) do
80
+ lambdaTelescope info.value fun xs body => do
81
+ let us := info.levelParams.map mkLevelParam
82
+ let type ← mkEq (mkAppN (Lean.mkConst declName us) xs) body
83
+ let goal ← withNewMCtxDepth do
84
+ try
85
+ let goal ← mkFreshExprSyntheticOpaqueMVar type
86
+ let mvarId := goal.mvarId!
87
+ trace[Elab.definition.partialFixpoint] "mkUnfoldEq start:{mvarId}"
88
+ let mvarId ← deltaLHSUntilFix declName info.declNameNonRec mvarId
89
+ trace[Elab.definition.partialFixpoint] "mkUnfoldEq after deltaLHS:{mvarId}"
90
+ let mvarId ← rwFixEq mvarId
91
+ trace[Elab.definition.partialFixpoint] "mkUnfoldEq after rwFixEq:{mvarId}"
92
+ withAtLeastTransparency .all <|
93
+ withOptions (smartUnfolding.set · false) <|
94
+ mvarId.refl
95
+ trace[Elab.definition.partialFixpoint] "mkUnfoldEq rfl succeeded"
96
+ instantiateMVars goal
97
+ catch e =>
98
+ throwError "failed to generate unfold theorem for '{declName}':\n{e.toMessageData}"
99
+ let type ← mkForallFVars xs type
100
+ let type ← letToHave type
101
+ let value ← mkLambdaFVars xs goal
102
+ addDecl <| Declaration.thmDecl {
103
+ name, type, value
104
+ levelParams := info.levelParams
105
+ }
106
+
107
+ def getUnfoldFor? (declName : Name) : MetaM (Option Name) := do
108
+ let name := mkEqLikeNameFor (← getEnv) declName unfoldThmSuffix
109
+ let env ← getEnv
110
+ if env.contains name then return name
111
+ let some info := eqnInfoExt.find? env declName | return none
112
+ return some (← mkUnfoldEq declName info)
113
+
114
+ def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
115
+ if let some info := eqnInfoExt.find? (← getEnv) declName then
116
+ mkEqns declName info.declNames
117
+ else
118
+ return none
119
+
120
+ builtin_initialize
121
+ registerGetEqnsFn getEqnsFor?
122
+ registerGetUnfoldEqnFn getUnfoldFor?
123
+
124
+ end Lean.Elab.PartialFixpoint
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Induction.lean ADDED
@@ -0,0 +1,402 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Joachim Breitner
5
+ -/
6
+
7
+ prelude
8
+ import Lean.Meta.Basic
9
+ import Lean.Meta.Match.MatcherApp.Transform
10
+ import Lean.Meta.Check
11
+ import Lean.Meta.Tactic.Subst
12
+ import Lean.Meta.Injective -- for elimOptParam
13
+ import Lean.Meta.ArgsPacker
14
+ import Lean.Meta.PProdN
15
+ import Lean.Meta.Tactic.Apply
16
+ import Lean.Elab.PreDefinition.PartialFixpoint.Eqns
17
+ import Lean.Elab.Command
18
+ import Lean.Meta.Tactic.ElimInfo
19
+
20
+ namespace Lean.Elab.PartialFixpoint
21
+
22
+ open Lean Elab Meta
23
+
24
+ open Lean.Order
25
+
26
+ def mkAdmAnd (α instα adm₁ adm₂ : Expr) : MetaM Expr :=
27
+ mkAppOptM ``admissible_and #[α, instα, none, none, adm₁, adm₂]
28
+
29
+ partial def mkAdmProj (packedInst : Expr) (i : Nat) (e : Expr) : MetaM Expr := do
30
+ if let some inst ← whnfUntil packedInst ``instCCPOPProd then
31
+ let_expr instCCPOPProd α β instα instβ := inst | throwError "mkAdmProj: unexpected instance {inst}"
32
+ if i == 0 then
33
+ mkAppOptM ``admissible_pprod_fst #[α, β, instα, instβ, none, e]
34
+ else
35
+ let e ← mkAdmProj instβ (i - 1) e
36
+ mkAppOptM ``admissible_pprod_snd #[α, β, instα, instβ, none, e]
37
+ else
38
+ assert! i == 0
39
+ return e
40
+
41
+ def CCPOProdProjs (n : Nat) (inst : Expr) : Array Expr := Id.run do
42
+ let mut insts := #[inst]
43
+ while insts.size < n do
44
+ let inst := insts.back!
45
+ let_expr Lean.Order.instCCPOPProd _ _ inst₁ inst₂ := inst
46
+ | panic! s!"isOptionFixpoint: unexpected CCPO instance {inst}"
47
+ insts := insts.pop
48
+ insts := insts.push inst₁
49
+ insts := insts.push inst₂
50
+ return insts
51
+
52
+ /--
53
+ Unfolds an appropriate `PartialOrder` instance on predicates to quantifications and implications.
54
+ I.e. `ImplicationOrder.instPartialOrder.rel P Q` becomes
55
+ `∀ x y, P x y → Q x y`.
56
+ In the premise of the Park induction principle (`lfp_le_of_le_monotone`) we use a monotone map defining the predicate in the eta expanded form. In such a case, besides desugaring the predicate, we need to perform a weak head reduction.
57
+ The optional parameter `reduceConclusion` (false by default) indicates whether we need to perform this reduction.
58
+ -/
59
+ def unfoldPredRel (predType : Expr) (body : Expr) (fixpointType : PartialFixpointType) (reduceConclusion : Bool := false) : MetaM Expr := do
60
+ match fixpointType with
61
+ | .partialFixpoint => throwError "Trying to apply lattice induction to a non-lattice fixpoint. Please report this issue."
62
+ | .inductiveFixpoint | .coinductiveFixpoint =>
63
+ unless body.isAppOfArity ``PartialOrder.rel 4 do
64
+ throwError "{body} is not an application of partial order"
65
+ let lhsTypes ← forallTelescope predType fun ts _ => ts.mapM inferType
66
+ let names ← lhsTypes.mapM fun _ => mkFreshUserName `x
67
+ let bodyArgs := body.getAppArgs
68
+ withLocalDeclsDND (names.zip lhsTypes) fun exprs => do
69
+ let mut applied := match fixpointType with
70
+ | .inductiveFixpoint => (bodyArgs[2]!, bodyArgs[3]!)
71
+ | .coinductiveFixpoint => (bodyArgs[3]!, bodyArgs[2]!)
72
+ | .partialFixpoint => panic! "Cannot apply lattice induction to a non-lattice fixpoint"
73
+ for e in exprs do
74
+ applied := (mkApp applied.1 e, mkApp applied.2 e)
75
+ if reduceConclusion then
76
+ match fixpointType with
77
+ | .inductiveFixpoint => applied := ((←whnf applied.1), applied.2)
78
+ | .coinductiveFixpoint => applied := (applied.1, (←whnf applied.2))
79
+ | .partialFixpoint => throwError "Cannot apply lattice induction to a non-lattice fixpoint"
80
+ mkForallFVars exprs (←mkArrow applied.1 applied.2)
81
+
82
+ /-- `maskArray mask xs` keeps those `x` where the corresponding entry in `mask` is `true` -/
83
+ -- Worth having in the standard library?
84
+ private def maskArray {α} (mask : Array Bool) (xs : Array α) : Array α := Id.run do
85
+ let mut ys := #[]
86
+ for b in mask, x in xs do
87
+ if b then ys := ys.push x
88
+ return ys
89
+
90
+ /-- Appends `_1` etc to `base` unless `n == 1` -/
91
+ private def numberNames (n : Nat) (base : String) : Array Name :=
92
+ .ofFn (n := n) fun ⟨i, _⟩ =>
93
+ if n == 1 then .mkSimple base else .mkSimple s!"{base}_{i+1}"
94
+
95
+ def getInductionPrinciplePostfix (name : Name) : MetaM Name := do
96
+ let some eqnInfo := eqnInfoExt.find? (← getEnv) name | throwError "{name} is not defined by partial_fixpoint, inductive_fixpoint, nor coinductive_fixpoint"
97
+ let idx := eqnInfo.declNames.idxOf name
98
+ let some res := eqnInfo.fixpointType[idx]? | throwError "Cannot get fixpoint type for {name}"
99
+ match res with
100
+ | .partialFixpoint => return `fixpoint_induct
101
+ | .inductiveFixpoint => return `induct
102
+ | .coinductiveFixpoint => return `coinduct
103
+
104
+ def deriveInduction (name : Name) : MetaM Unit := do
105
+ let postFix ← getInductionPrinciplePostfix name
106
+ let inductName := name ++ postFix
107
+ realizeConst name inductName do
108
+ trace[Elab.definition.partialFixpoint] "Called deriveInduction for {inductName}"
109
+ prependError m!"Cannot derive fixpoint induction principle (please report this issue)" do
110
+ let some eqnInfo := eqnInfoExt.find? (← getEnv) name |
111
+ throwError "{name} is not defined by partial_fixpoint"
112
+ let infos ← eqnInfo.declNames.mapM getConstInfoDefn
113
+ let e' ← eqnInfo.fixedParamPerms.perms[0]!.forallTelescope infos[0]!.type fun xs => do
114
+ -- Now look at the body of an arbitrary of the functions (they are essentially the same
115
+ -- up to the final projections)
116
+ let body ← eqnInfo.fixedParamPerms.perms[0]!.instantiateLambda infos[0]!.value xs
117
+
118
+ -- The body should now be of the form of the form (fix … ).2.2.1
119
+ -- We strip the projections (if present)
120
+ let body' := PProdN.stripProjs body.eta -- TODO: Eta more carefully?
121
+ if eqnInfo.fixpointType.all isLatticeTheoretic then
122
+ unless eqnInfo.declNames.size == 1 do
123
+ throwError "Mutual lattice (co)induction is not supported yet"
124
+
125
+ -- We strip it until we reach an application of `lfp_montotone`
126
+ let some fixApp ← whnfUntil body' ``lfp_monotone
127
+ | throwError "Unexpected function body {body}, could not whnfUntil lfp_monotone"
128
+ let_expr lfp_monotone α instcomplete_lattice F hmono := fixApp
129
+ | throwError "Unexpected function body {body}, not an application of lfp_monotone"
130
+ let e' ← mkAppOptM ``lfp_le_of_le_monotone #[α, instcomplete_lattice, F, hmono]
131
+
132
+ -- We get the type of the induction principle
133
+ let eTyp ← inferType e'
134
+ let f ← mkConstWithLevelParams infos[0]!.name
135
+ let fEtaExpanded ← lambdaTelescope infos[0]!.value fun ys _ =>
136
+ mkLambdaFVars ys (mkAppN f ys)
137
+ let fInst ← eqnInfo.fixedParamPerms.perms[0]!.instantiateLambda fEtaExpanded xs
138
+ let fInst := fInst.eta
139
+
140
+ -- Then, we change the conclusion so it doesn't mention the `lfp_monotone`, but rather the actual predicate.
141
+ let newTyp ← forallTelescope eTyp fun args econc =>
142
+ if econc.isAppOfArity ``PartialOrder.rel 4 then
143
+ let oldArgs := econc.getAppArgs
144
+ let newArgs := oldArgs.set! 2 fInst
145
+ let newBody := mkAppN econc.getAppFn newArgs
146
+ mkForallFVars args newBody
147
+ else
148
+ throwError "Unexpected conclusion of the fixpoint induction principle: {econc}"
149
+
150
+ -- Desugar partial order on predicates in premises and conclusion
151
+ let newTyp ← forallTelescope newTyp fun args conclusion => do
152
+ let predicate := args[0]!
153
+ let predicateType ← inferType predicate
154
+ let premise := args[1]!
155
+ let premiseType ← inferType premise
156
+ -- Besides unfolding the predicate, we need to perform a weak head reduction in the premise,
157
+ -- where the monotone map defining the fixpoint is in the eta expanded form.
158
+ -- We do this by setting the optional parameter `reduceConclusion` to true.
159
+ let premiseType ← unfoldPredRel predicateType premiseType eqnInfo.fixpointType[0]! (reduceConclusion := true)
160
+ let newConclusion ← unfoldPredRel predicateType conclusion eqnInfo.fixpointType[0]!
161
+ let abstracedNewConclusion ← mkForallFVars args newConclusion
162
+ withLocalDecl `y BinderInfo.default premiseType fun newPremise => do
163
+ let typeHint ← mkExpectedTypeHint newPremise premiseType
164
+ let argsForInst := args.set! 1 typeHint
165
+ let argsWithNewPremise := args.set! 1 newPremise
166
+ let instantiated ← instantiateForall abstracedNewConclusion argsForInst
167
+ mkForallFVars argsWithNewPremise instantiated
168
+
169
+ let e' ← mkExpectedTypeHint e' newTyp
170
+ let e' ← mkLambdaFVars (binderInfoForMVars := .default) (usedOnly := true) xs e'
171
+
172
+ trace[Elab.definition.partialFixpoint.induction] "Complete body of (lattice-theoretic) fixpoint induction principle:{indentExpr e'}"
173
+
174
+ pure e'
175
+ else
176
+ let some fixApp ← whnfUntil body' ``fix
177
+ | throwError "Unexpected function body {body}, could not whnfUntil fix"
178
+ let_expr fix α instCCPOα F hmono := fixApp
179
+ | throwError "Unexpected function body {body'}, not an application of fix"
180
+
181
+ let instCCPOs := CCPOProdProjs infos.size instCCPOα
182
+ let types ← infos.mapIdxM (eqnInfo.fixedParamPerms.perms[·]!.instantiateForall ·.type xs)
183
+ let packedType ← PProdN.pack 0 types
184
+ let motiveTypes ← types.mapM (mkArrow · (.sort 0))
185
+ let motiveNames := numberNames motiveTypes.size "motive"
186
+ withLocalDeclsDND (motiveNames.zip motiveTypes) fun motives => do
187
+ let packedMotive ←
188
+ withLocalDeclD (← mkFreshUserName `x) packedType fun x => do
189
+ mkLambdaFVars #[x] <| ← PProdN.pack 0 <|
190
+ motives.mapIdx fun idx motive =>
191
+ mkApp motive (PProdN.proj motives.size idx packedType x)
192
+
193
+ let admTypes ← motives.mapIdxM fun i motive => do
194
+ mkAppOptM ``admissible #[types[i]!, instCCPOs[i]!, some motive]
195
+ let admNames := numberNames admTypes.size "adm"
196
+ withLocalDeclsDND (admNames.zip admTypes) fun adms => do
197
+ let adms' ← adms.mapIdxM fun i adm => mkAdmProj instCCPOα i adm
198
+ let packedAdm ← PProdN.genMk (mkAdmAnd α instCCPOα) adms'
199
+ let hNames := numberNames infos.size "h"
200
+ let hTypes_hmask : Array (Expr × Array Bool) ← infos.mapIdxM fun i _info => do
201
+ let approxNames := infos.map fun info =>
202
+ match info.name with
203
+ | .str _ n => .mkSimple n
204
+ | _ => `f
205
+ withLocalDeclsDND (approxNames.zip types) fun approxs => do
206
+ let ihTypes := approxs.mapIdx fun j approx => mkApp motives[j]! approx
207
+ withLocalDeclsDND (ihTypes.map (⟨`ih, ·⟩)) fun ihs => do
208
+ let f ← PProdN.mk 0 approxs
209
+ let Ff := F.beta #[f]
210
+ let Ffi := PProdN.proj motives.size i packedType Ff
211
+ let t := mkApp motives[i]! Ffi
212
+ let t ← PProdN.reduceProjs t
213
+ let mask := approxs.map fun approx => t.containsFVar approx.fvarId!
214
+ let t ← mkForallFVars (maskArray mask approxs ++ maskArray mask ihs) t
215
+ pure (t, mask)
216
+ let (hTypes, masks) := hTypes_hmask.unzip
217
+ withLocalDeclsDND (hNames.zip hTypes) fun hs => do
218
+ let packedH ←
219
+ withLocalDeclD `approx packedType fun approx =>
220
+ let packedIHType := packedMotive.beta #[approx]
221
+ withLocalDeclD `ih packedIHType fun ih => do
222
+ let approxs := PProdN.projs motives.size packedType approx
223
+ let ihs := PProdN.projs motives.size packedIHType ih
224
+ let e ← PProdN.mk 0 <| hs.mapIdx fun i h =>
225
+ let mask := masks[i]!
226
+ mkAppN h (maskArray mask approxs ++ maskArray mask ihs)
227
+ mkLambdaFVars #[approx, ih] e
228
+ let e' ← mkAppOptM ``fix_induct #[α, instCCPOα, F, hmono, packedMotive, packedAdm, packedH]
229
+ -- Should be the type of e', but with the function definitions folded
230
+ let packedConclusion ← PProdN.pack 0 <| ←
231
+ motives.mapIdxM fun i motive => do
232
+ let f ← mkConstWithLevelParams infos[i]!.name
233
+ let fEtaExpanded ← lambdaTelescope infos[i]!.value fun ys _ =>
234
+ mkLambdaFVars ys (mkAppN f ys)
235
+ let fInst ← eqnInfo.fixedParamPerms.perms[i]!.instantiateLambda fEtaExpanded xs
236
+ let fInst := fInst.eta
237
+ return mkApp motive fInst
238
+ let e' ← mkExpectedTypeHint e' packedConclusion
239
+ let e' ← mkLambdaFVars hs e'
240
+ let e' ← mkLambdaFVars adms e'
241
+ let e' ← mkLambdaFVars motives e'
242
+ let e' ← mkLambdaFVars (binderInfoForMVars := .default) (usedOnly := true) xs e'
243
+ let e' ← instantiateMVars e'
244
+ trace[Elab.definition.partialFixpoint.induction] "complete body of fixpoint induction principle:{indentExpr e'}"
245
+ pure e'
246
+
247
+ let eTyp ← inferType e'
248
+ let eTyp ← elimOptParam eTyp
249
+ -- logInfo m!"eTyp: {eTyp}"
250
+ let params := (collectLevelParams {} eTyp).params
251
+ -- Prune unused level parameters, preserving the original order
252
+ let us := infos[0]!.levelParams.filter (params.contains ·)
253
+
254
+ addDecl <| Declaration.thmDecl
255
+ { name := inductName, levelParams := us, type := eTyp, value := e' }
256
+
257
+ def isInductName (env : Environment) (name : Name) : Bool := Id.run do
258
+ let .str p s := name | return false
259
+ match s with
260
+ | "fixpoint_induct" =>
261
+ if let some eqnInfo := eqnInfoExt.find? env p then
262
+ return p == eqnInfo.declNames[0]! && isPartialFixpoint (eqnInfo.fixpointType[0]!)
263
+ return false
264
+ | "coinduct" =>
265
+ if let some eqnInfo := eqnInfoExt.find? env p then
266
+ let idx := eqnInfo.declNames.idxOf p
267
+ return isCoinductiveFixpoint eqnInfo.fixpointType[idx]!
268
+ return false
269
+ | "induct" =>
270
+ if let some eqnInfo := eqnInfoExt.find? env p then
271
+ let idx := eqnInfo.declNames.idxOf p
272
+ return isInductiveFixpoint eqnInfo.fixpointType[idx]!
273
+ return false
274
+ | _ => return false
275
+
276
+ builtin_initialize
277
+ registerReservedNamePredicate isInductName
278
+
279
+ registerReservedNameAction fun name => do
280
+ if isInductName (← getEnv) name then
281
+ let .str p _ := name | return false
282
+ MetaM.run' <| deriveInduction p
283
+ return true
284
+ return false
285
+
286
+ /--
287
+ Returns true if `name` defined by `partial_fixpoint`, the first in its mutual group,
288
+ and all functions are defined using the `CCPO` instance for `Option`.
289
+ -/
290
+ def isOptionFixpoint (env : Environment) (name : Name) : Bool := Option.isSome do
291
+ let eqnInfo ← eqnInfoExt.find? env name
292
+ guard <| name == eqnInfo.declNames[0]!
293
+ let defnInfo ← env.find? eqnInfo.declNameNonRec
294
+ assert! defnInfo.hasValue
295
+ let mut value := defnInfo.value!
296
+ while value.isLambda do value := value.bindingBody!
297
+ let_expr Lean.Order.fix _ inst _ _ := value | panic! s!"isOptionFixpoint: unexpected value {value}"
298
+ let insts := CCPOProdProjs eqnInfo.declNames.size inst
299
+ insts.forM fun inst => do
300
+ let mut inst := inst
301
+ while inst.isAppOfArity ``instCCPOPi 3 do
302
+ guard inst.appArg!.isLambda
303
+ inst := inst.appArg!.bindingBody!
304
+ guard <| inst.isAppOfArity ``instCCPOOption 1
305
+
306
+ def isPartialCorrectnessName (env : Environment) (name : Name) : Bool := Id.run do
307
+ let .str p s := name | return false
308
+ unless s == "partial_correctness" do return false
309
+ return isOptionFixpoint env p
310
+
311
+ /--
312
+ Given `motive : α → β → γ → Prop`, construct a proof of
313
+ `admissible (fun f => ∀ x y r, f x y = r → motive x y r)`
314
+ -/
315
+ def mkOptionAdm (motive : Expr) : MetaM Expr := do
316
+ let type ← inferType motive
317
+ forallTelescope type fun ysr _ => do
318
+ let P := mkAppN motive ysr
319
+ let ys := ysr.pop
320
+ let r := ysr.back!
321
+ let mut inst ← mkAppM ``Option.admissible_eq_some #[P, r]
322
+ inst ← mkLambdaFVars #[r] inst
323
+ inst ← mkAppOptM ``admissible_pi #[none, none, none, none, inst]
324
+ for y in ys.reverse do
325
+ inst ← mkLambdaFVars #[y] inst
326
+ inst ← mkAppOptM ``admissible_pi_apply #[none, none, none, none, inst]
327
+ pure inst
328
+
329
+ def derivePartialCorrectness (name : Name) : MetaM Unit := do
330
+ let inductName := name ++ `partial_correctness
331
+ realizeConst name inductName do
332
+ let fixpointInductThm := name ++ `fixpoint_induct
333
+ unless (← getEnv).contains fixpointInductThm do
334
+ deriveInduction name
335
+
336
+ prependError m!"Cannot derive partial correctness theorem (please report this issue)" do
337
+ let some eqnInfo := eqnInfoExt.find? (← getEnv) name |
338
+ throwError "{name} is not defined by partial_fixpoint"
339
+
340
+ let infos ← eqnInfo.declNames.mapM getConstInfoDefn
341
+ let fixedParamPerm0 := eqnInfo.fixedParamPerms.perms[0]!
342
+ -- First open up the fixed parameters everywhere
343
+ let e' ← fixedParamPerm0.forallTelescope infos[0]!.type fun xs => do
344
+ let types ← infos.mapIdxM (eqnInfo.fixedParamPerms.perms[·]!.instantiateForall ·.type xs)
345
+
346
+ -- for `f : α → β → Option γ`, we expect a `motive : α → β → γ → Prop`
347
+ let motiveTypes ← types.mapM fun type =>
348
+ forallTelescopeReducing type fun ys type => do
349
+ let type ← whnf type
350
+ let_expr Option γ := type | throwError "Expected `Option`, got:{indentExpr type}"
351
+ withLocalDeclD (← mkFreshUserName `r) γ fun r =>
352
+ mkForallFVars (ys.push r) (.sort 0)
353
+ let motiveDecls ← motiveTypes.mapIdxM fun i motiveType => do
354
+ let n := if infos.size = 1 then .mkSimple "motive"
355
+ else .mkSimple s!"motive_{i+1}"
356
+ pure (n, fun _ => pure motiveType)
357
+ withLocalDeclsD motiveDecls fun motives => do
358
+ -- the motives, as expected by `f.fixpoint_induct`:
359
+ -- fun f => ∀ x y r, f x y = some r → motive x y r
360
+ let motives' ← motives.mapIdxM fun i motive => do
361
+ withLocalDeclD (← mkFreshUserName `f) types[i]! fun f => do
362
+ forallTelescope (← inferType motive) fun ysr _ => do
363
+ let ys := ysr.pop
364
+ let r := ysr.back!
365
+ let heq ← mkEq (mkAppN f ys) (← mkAppM ``some #[r])
366
+ let motive' ← mkArrow heq (mkAppN motive ysr)
367
+ let motive' ← mkForallFVars ysr motive'
368
+ mkLambdaFVars #[f] motive'
369
+
370
+ let e' ← mkAppOptM fixpointInductThm <| (xs ++ motives').map some
371
+ let adms ← motives.mapM mkOptionAdm
372
+ let e' := mkAppN e' adms
373
+ let e' ← mkLambdaFVars motives e'
374
+ let e' ← mkLambdaFVars (binderInfoForMVars := .default) (usedOnly := true) xs e'
375
+ let e' ← instantiateMVars e'
376
+ trace[Elab.definition.partialFixpoint.induction] "complete body of partial correctness principle:{indentExpr e'}"
377
+ pure e'
378
+
379
+ let eTyp ← inferType e'
380
+ let eTyp ← elimOptParam eTyp
381
+ let eTyp ← Core.betaReduce eTyp
382
+ -- logInfo m!"eTyp: {eTyp}"
383
+ let params := (collectLevelParams {} eTyp).params
384
+ -- Prune unused level parameters, preserving the original order
385
+ let us := infos[0]!.levelParams.filter (params.contains ·)
386
+
387
+ addDecl <| Declaration.thmDecl
388
+ { name := inductName, levelParams := us, type := eTyp, value := e' }
389
+
390
+ builtin_initialize
391
+ registerReservedNamePredicate isPartialCorrectnessName
392
+
393
+ registerReservedNameAction fun name => do
394
+ let .str p s := name | return false
395
+ unless s == "partial_correctness" do return false
396
+ unless isOptionFixpoint (← getEnv) p do return false
397
+ MetaM.run' <| derivePartialCorrectness p
398
+ return false
399
+
400
+ end Lean.Elab.PartialFixpoint
401
+
402
+ builtin_initialize Lean.registerTraceClass `Elab.definition.partialFixpoint.induction
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Main.lean ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Elab.PreDefinition.MkInhabitant
8
+ import Lean.Elab.PreDefinition.Mutual
9
+ import Lean.Elab.PreDefinition.PartialFixpoint.Eqns
10
+ import Lean.Elab.Tactic.Monotonicity
11
+ import Init.Internal.Order.Basic
12
+ import Lean.Meta.PProdN
13
+ import Lean.Meta.Order
14
+
15
+ namespace Lean.Elab
16
+
17
+ open Meta
18
+ open Monotonicity
19
+
20
+ open Lean.Order
21
+
22
+ private def replaceRecApps (recFnNames : Array Name) (fixedParamPerms : FixedParamPerms) (f : Expr) (e : Expr) : MetaM Expr := do
23
+ assert! recFnNames.size = fixedParamPerms.perms.size
24
+ let t ← inferType f
25
+ return e.replace fun e => do
26
+ let fn := e.getAppFn
27
+ guard fn.isConst
28
+ let idx ← recFnNames.idxOf? fn.constName!
29
+ let args := e.getAppArgs
30
+ let varying := fixedParamPerms.perms[idx]!.pickVarying args
31
+ return mkAppN (PProdN.proj recFnNames.size idx t f) varying
32
+
33
+ /--
34
+ For pretty error messages:
35
+ Takes `F : (fun f => e)`, where `f` is the packed function, and replaces `f` in `e` with the user-visible
36
+ constants, which are added to the environment temporarily.
37
+ -/
38
+ private def unReplaceRecApps {α} (preDefs : Array PreDefinition) (fixedParamPerms : FixedParamPerms) (fixedArgs : Array Expr)
39
+ (F : Expr) (k : Expr → MetaM α) : MetaM α := do
40
+ unless F.isLambda do throwError "Expected lambda:{indentExpr F}"
41
+ withoutModifyingEnv do
42
+ preDefs.forM addAsAxiom
43
+ let fns ← preDefs.mapIdxM fun funIdx preDef => do
44
+ let value ← fixedParamPerms.perms[funIdx]!.instantiateLambda preDef.value fixedArgs
45
+ lambdaTelescope value fun xs _ =>
46
+ let args := fixedParamPerms.perms[funIdx]!.buildArgs fixedArgs xs
47
+ let call := mkAppN (.const preDef.declName (preDef.levelParams.map mkLevelParam)) args
48
+ mkLambdaFVars (etaReduce := true) xs call
49
+ let packedFn ← PProdN.mk 0 fns
50
+ let e ← lambdaBoundedTelescope F 1 fun f e => do
51
+ let f := f[0]!
52
+ -- Replace f with calls to the constants
53
+ let e := e.replace fun e => do
54
+ if e == f then return packedFn else none
55
+ -- And reduce projection and beta redexes
56
+ -- (This is a bit blunt; we could try harder to only replace the projection and beta-redexes
57
+ -- introduced above)
58
+ let e ← PProdN.reduceProjs e
59
+ let e ← Core.betaReduce e
60
+ pure e
61
+ k e
62
+
63
+ /--
64
+ Given two type-proof pairs for `monotone f` and `monotone g`, constructs a type-proof pair for `monotone fun x => ⟨f x, g x⟩`.
65
+ -/
66
+ private def mkMonoPProd : (hmono₁ hmono₂ : Expr × Expr) → MetaM (Expr × Expr)
67
+ | (hmono1Type, hmono1Proof), (hmono2Type, hmono2Proof) => do
68
+ -- mkAppM does not support the equivalent of (cfg := { synthAssignedInstances := false}),
69
+ -- so this is a bit more pedestrian
70
+ let_expr monotone _ inst _ inst₁ _ := hmono1Type
71
+ | throwError "mkMonoPProd: unexpected type of{indentExpr hmono1Proof}"
72
+ let_expr monotone _ _ _ inst₂ _ := hmono2Type
73
+ | throwError "mkMonoPProd: unexpected type of{indentExpr hmono2Proof}"
74
+ let hmonoProof ← mkAppOptM ``PProd.monotone_mk #[none, none, none, inst₁, inst₂, inst, none, none, hmono1Proof, hmono2Proof]
75
+ return (← inferType hmonoProof, hmonoProof)
76
+
77
+ def partialFixpoint (preDefs : Array PreDefinition) : TermElabM Unit := do
78
+ -- We expect all functions in the clique to have `partial_fixpoint`, `inductive_fixpoint` or `coinductive_fixpoint` syntax
79
+ let hints := preDefs.filterMap (·.termination.partialFixpoint?)
80
+ assert! preDefs.size = hints.size
81
+ -- We check if any fixpoints were defined lattice-theoretically
82
+ if hints.any fun x => isLatticeTheoretic x.fixpointType then
83
+ -- If yes, then we expect all of them to be defined using lattice theory
84
+ assert! hints.all fun x => isLatticeTheoretic x.fixpointType
85
+
86
+ -- For every function of type `∀ x y, r x y`, an CCPO instance
87
+ -- ∀ x y, CCPO (r x y), but crucially constructed using `instCCPOPi`
88
+ let insts ← preDefs.mapIdxM fun i preDef => withRef hints[i]!.ref do
89
+ lambdaTelescope preDef.value fun xs _body => do
90
+ let type ← instantiateForall preDef.type xs
91
+ let inst ←
92
+ match hints[i]!.fixpointType with
93
+ | .coinductiveFixpoint =>
94
+ unless type.isProp do
95
+ throwError "`coinductive_fixpoint` can be only used to define predicates"
96
+ pure (mkConst ``ReverseImplicationOrder.instCompleteLattice)
97
+ | .inductiveFixpoint =>
98
+ unless type.isProp do
99
+ throwError "`inductive_fixpoint` can be only used to define predicates"
100
+ pure (mkConst ``ImplicationOrder.instCompleteLattice)
101
+ | .partialFixpoint => try
102
+ synthInstance (← mkAppM ``CCPO #[type])
103
+ catch _ =>
104
+ trace[Elab.definition.partialFixpoint] "No CCPO instance found for {preDef.declName}, trying inhabitation"
105
+ let msg := m!"failed to compile definition '{preDef.declName}' using `partial_fixpoint`"
106
+ let w ← mkInhabitantFor msg #[] preDef.type
107
+ let instNonempty ← mkAppM ``Nonempty.intro #[mkAppN w xs]
108
+ let classicalWitness ← mkAppOptM ``Classical.ofNonempty #[none, instNonempty]
109
+ mkAppOptM ``FlatOrder.instCCPO #[none, classicalWitness]
110
+ mkLambdaFVars xs inst
111
+
112
+ let declNames := preDefs.map (·.declName)
113
+ let fixedParamPerms ← getFixedParamPerms preDefs
114
+ fixedParamPerms.perms[0]!.forallTelescope preDefs[0]!.type fun fixedArgs => do
115
+ -- Either: ∀ x y, CCPO (rᵢ x y)
116
+ -- Or: ∀ x y, CompleteLattice (rᵢ x y)
117
+ let insts ← insts.mapIdxM (fixedParamPerms.perms[·]!.instantiateLambda · fixedArgs)
118
+ let types ← preDefs.mapIdxM (fixedParamPerms.perms[·]!.instantiateForall ·.type fixedArgs)
119
+
120
+ -- (∀ x y, r₁ x y) ×' (∀ x y, r₂ x y)
121
+ let packedType ← PProdN.pack 0 types
122
+
123
+ -- Either: CCPO (∀ x y, rᵢ x y)
124
+ -- Or: CompleteLattice (∀ x y, rᵢ x y)
125
+ let insts' ← insts.mapM fun inst =>
126
+ lambdaTelescope inst fun xs inst => do
127
+ let mut inst := inst
128
+ for x in xs.reverse do
129
+ inst ← mkInstPiOfInstForall x inst
130
+ pure inst
131
+
132
+ -- Either: CCPO ((∀ x y, r₁ x y) ×' (∀ x y, r₂ x y))
133
+ -- Or: CompleteLattice ((∀ x y, r₁ x y) ×' (∀ x y, r₂ x y))
134
+ let packedInst ← mkPackedPPRodInstance insts'
135
+ -- Order ((∀ x y, r₁ x y) ×' (∀ x y, r₂ x y))
136
+ let packedPartialOrderInst ← toPartialOrder packedInst
137
+
138
+ -- Error reporting hook, presenting monotonicity errors in terms of recursive functions
139
+ let failK {α} f (monoThms : Array Name) : MetaM α := do
140
+ unReplaceRecApps preDefs fixedParamPerms fixedArgs f fun t => do
141
+ let extraMsg := if monoThms.isEmpty then m!"" else
142
+ m!"Tried to apply {.andList (monoThms.toList.map (m!"'{.ofConstName ·}'"))}, but failed.\n\
143
+ Possible cause: A missing `{.ofConstName ``MonoBind}` instance.\n\
144
+ Use `set_option trace.Elab.Tactic.monotonicity true` to debug."
145
+ if let some recApp := t.find? hasRecAppSyntax then
146
+ let some syn := getRecAppSyntax? recApp | panic! "getRecAppSyntax? failed"
147
+ withRef syn <|
148
+ throwError "Cannot eliminate recursive call `{syn}` enclosed in{indentExpr t}\n{extraMsg}"
149
+ else
150
+ throwError "Cannot eliminate recursive call in{indentExpr t}\n{extraMsg}"
151
+
152
+ -- Adjust the body of each function to take the other functions as a
153
+ -- (packed) parameter
154
+ let Fs ← preDefs.mapIdxM fun funIdx preDef => do
155
+ let body ← fixedParamPerms.perms[funIdx]!.instantiateLambda preDef.value fixedArgs
156
+ withLocalDeclD (← mkFreshUserName `f) packedType fun f => do
157
+ let body' ← withoutModifyingEnv do
158
+ -- replaceRecApps needs the constants in the env to typecheck things
159
+ preDefs.forM (addAsAxiom ·)
160
+ replaceRecApps declNames fixedParamPerms f body
161
+ mkLambdaFVars #[f] body'
162
+
163
+ -- Construct and solve monotonicity goals for each function separately
164
+ -- This way we preserve the user's parameter names as much as possible
165
+ -- and can (later) use the user-specified per-function tactic
166
+ let hmonos ← preDefs.mapIdxM fun i preDef => do
167
+ let type := types[i]!
168
+ let F := Fs[i]!
169
+ let inst ← toPartialOrder insts'[i]! type
170
+ let goal ← mkAppOptM ``monotone #[packedType, packedPartialOrderInst, type, inst, F]
171
+ if let some term := hints[i]!.term? then
172
+ let hmono ← Term.withSynthesize <| Term.elabTermEnsuringType term goal
173
+ let hmono ← instantiateMVars hmono
174
+ let mvars ← getMVars hmono
175
+ if mvars.isEmpty then
176
+ pure (goal, hmono)
177
+ else
178
+ discard <| Term.logUnassignedUsingErrorInfos mvars
179
+ pure (goal, ← mkSorry goal (synthetic := true))
180
+ else
181
+ let hmono ← mkFreshExprSyntheticOpaqueMVar goal
182
+ prependError m!"Could not prove '{preDef.declName}' to be monotone in its recursive calls:" do
183
+ solveMono failK hmono.mvarId!
184
+ trace[Elab.definition.partialFixpoint] "monotonicity proof for {preDef.declName}: {hmono}"
185
+ pure (goal, ← instantiateMVars hmono)
186
+ let (_, hmono) ← PProdN.genMk mkMonoPProd hmonos
187
+
188
+ let packedValue ← mkFixOfMonFun packedType packedInst hmono
189
+
190
+ trace[Elab.definition.partialFixpoint] "packedValue: {packedValue}"
191
+
192
+ let declName :=
193
+ if preDefs.size = 1 && fixedParamPerms.fixedArePrefix then
194
+ preDefs[0]!.declName
195
+ else
196
+ preDefs[0]!.declName ++ `mutual
197
+ let packedType' ← mkForallFVars fixedArgs packedType
198
+ let packedValue' ← mkLambdaFVars fixedArgs packedValue
199
+ let preDefNonRec := { preDefs[0]! with
200
+ declName := declName
201
+ type := packedType'
202
+ value := packedValue'}
203
+
204
+ let preDefsNonrec ← preDefs.mapIdxM fun fidx preDef => do
205
+ forallBoundedTelescope preDef.type fixedParamPerms.perms[fidx]!.size fun params _ => do
206
+ let fixed := fixedParamPerms.perms[fidx]!.pickFixed params
207
+ let varying := fixedParamPerms.perms[fidx]!.pickVarying params
208
+ let us := preDefNonRec.levelParams.map mkLevelParam
209
+ let value := mkConst preDefNonRec.declName us
210
+ let value := mkAppN value fixed
211
+ let value := PProdN.proj preDefs.size fidx packedType value
212
+ let value := mkAppN value varying
213
+ let value ← mkLambdaFVars (etaReduce := true) params value
214
+ pure { preDef with value }
215
+
216
+ Mutual.addPreDefsFromUnary preDefs preDefsNonrec preDefNonRec
217
+ addAndCompilePartialRec preDefs
218
+ let preDefs ← preDefs.mapM (Mutual.cleanPreDef ·)
219
+ PartialFixpoint.registerEqnsInfo preDefs preDefNonRec.declName fixedParamPerms (hints.map (·.fixpointType))
220
+ Mutual.addPreDefAttributes preDefs
221
+
222
+ end Lean.Elab
223
+
224
+ builtin_initialize Lean.registerTraceClass `Elab.definition.partialFixpoint
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/BRecOn.lean ADDED
@@ -0,0 +1,293 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Util.HasConstCache
8
+ import Lean.Meta.PProdN
9
+ import Lean.Meta.Match.MatcherApp.Transform
10
+ import Lean.Elab.RecAppSyntax
11
+ import Lean.Elab.PreDefinition.Basic
12
+ import Lean.Elab.PreDefinition.Structural.Basic
13
+ import Lean.Elab.PreDefinition.Structural.RecArgInfo
14
+
15
+ namespace Lean.Elab.Structural
16
+ open Meta
17
+
18
+ private def throwToBelowFailed : MetaM α :=
19
+ throwError "toBelow failed"
20
+
21
+ partial def searchPProd (e : Expr) (F : Expr) (k : Expr → Expr → MetaM α) : MetaM α := do
22
+ match (← whnf e) with
23
+ | .app (.app (.const `PProd _) d1) d2 =>
24
+ (do searchPProd d1 (.proj ``PProd 0 F) k)
25
+ <|> (do searchPProd d2 (.proj ``PProd 1 F) k)
26
+ | .app (.app (.const `And _) d1) d2 =>
27
+ (do searchPProd d1 (.proj `And 0 F) k)
28
+ <|> (do searchPProd d2 (.proj `And 1 F) k)
29
+ | .const `PUnit _
30
+ | .const `True _ => throwToBelowFailed
31
+ | _ => k e F
32
+
33
+ /-- See `toBelow` -/
34
+ private partial def toBelowAux (C : Expr) (belowDict : Expr) (arg : Expr) (F : Expr) : MetaM Expr := do
35
+ trace[Elab.definition.structural] "belowDict start:{indentExpr belowDict}\narg:{indentExpr arg}"
36
+ -- First search through the PProd packing of the different `brecOn` motives
37
+ searchPProd belowDict F fun belowDict F => do
38
+ trace[Elab.definition.structural] "belowDict step 1:{indentExpr belowDict}"
39
+ -- Then instantiate parameters of a reflexive type, if needed
40
+ forallTelescopeReducing belowDict fun xs belowDict => do
41
+ let arg ← zetaReduce arg
42
+ let argArgs := arg.getAppArgs
43
+ unless argArgs.size >= xs.size do throwToBelowFailed
44
+ let n := argArgs.size
45
+ let argTailArgs := argArgs.extract (n - xs.size) n
46
+ let belowDict := belowDict.replaceFVars xs argTailArgs
47
+ -- And again search through the PProd packing due to multiple functions recursing on the
48
+ -- same inductive data type
49
+ -- (We could use the funIdx and the `positions` array to replace this search with more
50
+ -- targeted indexing.)
51
+ searchPProd belowDict (mkAppN F argTailArgs) fun belowDict F => do
52
+ trace[Elab.definition.structural] "belowDict step 2:{indentExpr belowDict}"
53
+ match belowDict with
54
+ | .app belowDictFun belowDictArg =>
55
+ unless belowDictFun.getAppFn == C do throwToBelowFailed
56
+ unless ← isDefEq belowDictArg arg do throwToBelowFailed
57
+ pure F
58
+ | _ =>
59
+ trace[Elab.definition.structural] "belowDict not an app:{indentExpr belowDict}"
60
+ throwToBelowFailed
61
+
62
+ /-- See `toBelow` -/
63
+ private def withBelowDict [Inhabited α] (below : Expr) (numIndParams : Nat)
64
+ (positions : Positions) (k : Array Expr → Expr → MetaM α) : MetaM α := do
65
+ let numTypeFormers := positions.size
66
+ let belowType ← inferType below
67
+ trace[Elab.definition.structural] "belowType: {belowType}"
68
+ unless (← isTypeCorrect below) do
69
+ trace[Elab.definition.structural] "not type correct!"
70
+ belowType.withApp fun f args => do
71
+ unless numIndParams + numTypeFormers < args.size do
72
+ trace[Elab.definition.structural] "unexpected 'below' type{indentExpr belowType}"
73
+ throwToBelowFailed
74
+ let params := args[*...numIndParams]
75
+ let finalArgs := args[(numIndParams+numTypeFormers)...*]
76
+ let pre := mkAppN f params
77
+ let motiveTypes ← inferArgumentTypesN numTypeFormers pre
78
+ let numMotives : Nat := positions.numIndices
79
+ trace[Elab.definition.structural] "numMotives: {numMotives}"
80
+ let mut CTypes := Array.replicate numMotives (.sort 37) -- dummy value
81
+ for poss in positions, motiveType in motiveTypes do
82
+ for pos in poss do
83
+ CTypes := CTypes.set! pos motiveType
84
+ let CDecls : Array (Name × (Array Expr → MetaM Expr)) ← CTypes.mapM fun t => do
85
+ return ((← mkFreshUserName `C), fun _ => pure t)
86
+ withLocalDeclsD CDecls fun Cs => do
87
+ -- We have to pack these canary motives like we packed the real motives
88
+ let packedCs ← positions.mapMwith PProdN.packLambdas motiveTypes Cs
89
+ let belowDict := mkAppN pre packedCs
90
+ let belowDict := mkAppN belowDict finalArgs
91
+ trace[Elab.definition.structural] "initial belowDict for {Cs}:{indentExpr belowDict}"
92
+ unless (← isTypeCorrect belowDict) do
93
+ trace[Elab.definition.structural] "not type correct!"
94
+ k Cs belowDict
95
+
96
+ /--
97
+ `below` is a free variable with type of the form `I.below indParams motive indices major`,
98
+ where `I` is the name of an inductive datatype.
99
+
100
+ For example, when trying to show that the following function terminates using structural recursion
101
+ ```lean
102
+ def addAdjacent : List Nat → List Nat
103
+ | [] => []
104
+ | [a] => [a]
105
+ | a::b::as => (a+b) :: addAdjacent as
106
+ ```
107
+ when we are visiting `addAdjacent as` at `replaceRecApps`, `below` has type
108
+ `@List.below Nat (fun (x : List Nat) => List Nat) (a::b::as)`
109
+ The motive `fun (x : List Nat) => List Nat` depends on the actual function we are trying to compute.
110
+ So, we first replace it with a fresh variable `C` at `withBelowDict`.
111
+ Recall that `brecOn` implements course-of-values recursion, and `below` can be viewed as a dictionary
112
+ of the "previous values".
113
+ We search this dictionary using the auxiliary function `toBelowAux`.
114
+ The dictionary is built using the `PProd` (`And` for inductive predicates).
115
+ We keep searching it until we find `C recArg`, where `C` is the auxiliary fresh variable created at `withBelowDict`. -/
116
+ private partial def toBelow (below : Expr) (numIndParams : Nat) (positions : Positions) (fnIndex : Nat) (recArg : Expr) : MetaM Expr := do
117
+ withTraceNode `Elab.definition.structural (return m!"{exceptEmoji ·} searching IH for {recArg} in {←inferType below}") do
118
+ withBelowDict below numIndParams positions fun Cs belowDict =>
119
+ toBelowAux Cs[fnIndex]! belowDict recArg below
120
+
121
+ private partial def replaceRecApps (recArgInfos : Array RecArgInfo) (positions : Positions)
122
+ (below : Expr) (e : Expr) : M Expr :=
123
+ let recFnNames := recArgInfos.map (·.fnName)
124
+ let containsRecFn (e : Expr) : StateRefT (HasConstCache recFnNames) M Bool :=
125
+ modifyGet (·.contains e)
126
+ let rec loop (below : Expr) (e : Expr) : StateRefT (HasConstCache recFnNames) M Expr := do
127
+ if !(← containsRecFn e) then
128
+ return e
129
+ match e with
130
+ | Expr.lam n d b c =>
131
+ withLocalDecl n c (← loop below d) fun x => do
132
+ mkLambdaFVars #[x] (← loop below (b.instantiate1 x))
133
+ | Expr.forallE n d b c =>
134
+ withLocalDecl n c (← loop below d) fun x => do
135
+ mkForallFVars #[x] (← loop below (b.instantiate1 x))
136
+ | Expr.letE n type val body nondep =>
137
+ mapLetDecl n (← loop below type) (← loop below val) (nondep := nondep) (usedLetOnly := false) fun x => do
138
+ loop below (body.instantiate1 x)
139
+ | Expr.mdata d b =>
140
+ if let some stx := getRecAppSyntax? e then
141
+ withRef stx <| loop below b
142
+ else
143
+ return mkMData d (← loop below b)
144
+ | Expr.proj n i e => return mkProj n i (← loop below e)
145
+ | Expr.app _ _ =>
146
+ let processApp (e : Expr) : StateRefT (HasConstCache recFnNames) M Expr :=
147
+ e.withApp fun f args => do
148
+ if let .some fnIdx := recArgInfos.findFinIdx? (f.isConstOf ·.fnName) then
149
+ let recArgInfo := recArgInfos[fnIdx]
150
+ let some recArg := args[recArgInfo.recArgPos]?
151
+ | throwError "insufficient number of parameters at recursive application {indentExpr e}"
152
+ -- For reflexive type, we may have nested recursive applications in recArg
153
+ let recArg ← loop below recArg
154
+ let f ←
155
+ try toBelow below recArgInfo.indGroupInst.params.size positions fnIdx recArg
156
+ catch _ => throwError "failed to eliminate recursive application{indentExpr e}"
157
+ -- We don't pass the fixed parameters, the indices and the major arg to `f`, only the rest
158
+ let ys := recArgInfo.fixedParamPerm.pickVarying args
159
+ let (_, fArgs) := recArgInfo.pickIndicesMajor ys
160
+ let fArgs ← fArgs.mapM (replaceRecApps recArgInfos positions below ·)
161
+ return mkAppN f fArgs
162
+ else
163
+ return mkAppN (← loop below f) (← args.mapM (loop below))
164
+ match (← matchMatcherApp? (alsoCasesOn := true) e) with
165
+ | some matcherApp =>
166
+ if recArgInfos.all (fun recArgInfo => !recArgHasLooseBVarsAt recArgInfo.fnName recArgInfo.recArgPos e) then
167
+ processApp e
168
+ else
169
+ /- Here is an example we currently do not handle
170
+ ```
171
+ def g (xs : List Nat) : Nat :=
172
+ match xs with
173
+ | [] => 0
174
+ | y::ys =>
175
+ match ys with
176
+ | [] => 1
177
+ | _::_::zs => g zs + 1
178
+ | zs => g ys + 2
179
+ ```
180
+ We are matching on `ys`, but still using `ys` in the third alternative.
181
+ If we push the `below` argument over the dependent match it will be able to eliminate recursive call using `zs`.
182
+ To make it work, users have to write the third alternative as `| zs => g zs + 2`
183
+ If this is too annoying in practice, we may replace `ys` with the matching term, but
184
+ this may generate weird error messages, when it doesn't work. -/
185
+ trace[Elab.definition.structural] "below before matcherApp.addArg: {below} : {← inferType below}"
186
+ if let some matcherApp ← matcherApp.addArg? below then
187
+ let altsNew ← (Array.zip matcherApp.alts matcherApp.altNumParams).mapM fun (alt, numParams) =>
188
+ lambdaBoundedTelescope alt numParams fun xs altBody => do
189
+ trace[Elab.definition.structural] "altNumParams: {numParams}, xs: {xs}"
190
+ unless xs.size = numParams do
191
+ throwError "unexpected matcher application alternative{indentExpr alt}\nat application{indentExpr e}"
192
+ let belowForAlt := xs[numParams - 1]!
193
+ mkLambdaFVars xs (← loop belowForAlt altBody)
194
+ pure { matcherApp with alts := altsNew }.toExpr
195
+ else
196
+ processApp e
197
+ | none => processApp e
198
+ | e =>
199
+ ensureNoRecFn recFnNames e
200
+ pure e
201
+ loop below e |>.run' {}
202
+
203
+ /--
204
+ Calculates the `.brecOn` motive corresponding to one structural recursive function.
205
+ The `value` is the function with (only) the fixed parameters moved into the context.
206
+ -/
207
+ def mkBRecOnMotive (recArgInfo : RecArgInfo) (value : Expr) : M Expr := do
208
+ lambdaTelescope value fun xs value => do
209
+ let type := (← inferType value).headBeta
210
+ let (indexMajorArgs, otherArgs) := recArgInfo.pickIndicesMajor xs
211
+ let motive ← mkForallFVars otherArgs type
212
+ mkLambdaFVars indexMajorArgs motive
213
+
214
+ /--
215
+ Calculates the `.brecOn` functional argument corresponding to one structural recursive function.
216
+ The `value` is the function with (only) the fixed parameters moved into the context,
217
+ The `FType` is the expected type of the argument.
218
+ The `recArgInfos` is used to transform the body of the function to replace recursive calls with
219
+ uses of the `below` induction hypothesis.
220
+ -/
221
+ def mkBRecOnF (recArgInfos : Array RecArgInfo) (positions : Positions)
222
+ (recArgInfo : RecArgInfo) (value : Expr) (FType : Expr) : M Expr := do
223
+ lambdaTelescope value fun xs value => do
224
+ let (indicesMajorArgs, otherArgs) := recArgInfo.pickIndicesMajor xs
225
+ let FType ← instantiateForall FType indicesMajorArgs
226
+ forallBoundedTelescope FType (some 1) fun below _ => do
227
+ -- TODO: `below` user name is `f`, and it will make a global `f` to be pretty printed as `_root_.f` in error messages.
228
+ -- We should add an option to `forallBoundedTelescope` to ensure fresh names are used.
229
+ let below := below[0]!
230
+ let valueNew ← replaceRecApps recArgInfos positions below value
231
+ mkLambdaFVars (indicesMajorArgs ++ #[below] ++ otherArgs) valueNew
232
+
233
+ /--
234
+ Given the `motives`, pass the right universe levels, the parameters, and the motives.
235
+ It was already checked earlier in `checkCodomainsLevel` that the functions live in the same universe.
236
+ -/
237
+ def mkBRecOnConst (recArgInfos : Array RecArgInfo) (positions : Positions)
238
+ (motives : Array Expr) : MetaM (Nat → Expr) := do
239
+ let indGroup := recArgInfos[0]!.indGroupInst
240
+ let motive := motives[0]!
241
+ let brecOnUniv ← lambdaTelescope motive fun _ type => getLevel type
242
+ let brecOnCons := fun idx => indGroup.brecOn brecOnUniv idx
243
+ -- Pick one as a prototype
244
+ let brecOnAux := brecOnCons 0
245
+ -- Infer the type of the packed motive arguments
246
+ let packedMotiveTypes ← inferArgumentTypesN indGroup.numMotives brecOnAux
247
+ let packedMotives ← positions.mapMwith PProdN.packLambdas packedMotiveTypes motives
248
+
249
+ return fun n => mkAppN (brecOnCons n) packedMotives
250
+
251
+ /--
252
+ Given the `recArgInfos` and the `motives`, infer the types of the `F` arguments to the `.brecOn`
253
+ combinators. This assumes that all `.brecOn` functions of a mutual inductive have the same structure.
254
+
255
+ It also undoes the permutation and packing done by `packMotives`
256
+ -/
257
+ def inferBRecOnFTypes (recArgInfos : Array RecArgInfo) (positions : Positions)
258
+ (brecOnConst : Nat → Expr) : MetaM (Array Expr) := do
259
+ let numTypeFormers := positions.size
260
+ let recArgInfo := recArgInfos[0]! -- pick an arbitrary one
261
+ let brecOn := brecOnConst recArgInfo.indIdx
262
+ check brecOn
263
+ let brecOnType ← inferType brecOn
264
+ -- Skip the indices and major argument
265
+ let packedFTypes ← forallBoundedTelescope brecOnType (some (recArgInfo.indicesPos.size + 1)) fun _ brecOnType =>
266
+ -- And return the types of the next arguments
267
+ arrowDomainsN numTypeFormers brecOnType
268
+
269
+ let mut FTypes := Array.replicate positions.numIndices (Expr.sort 0)
270
+ for packedFType in packedFTypes, poss in positions do
271
+ for pos in poss do
272
+ FTypes := FTypes.set! pos packedFType
273
+ return FTypes
274
+
275
+ /--
276
+ Completes the `.brecOn` for the given function.
277
+ The `value` is the function with (only) the fixed parameters moved into the context.
278
+ -/
279
+ def mkBrecOnApp (positions : Positions) (fnIdx : Nat) (brecOnConst : Nat → Expr)
280
+ (FArgs : Array Expr) (recArgInfo : RecArgInfo) (value : Expr) : MetaM Expr := do
281
+ lambdaTelescope value fun ys _value => do
282
+ let (indexMajorArgs, otherArgs) := recArgInfo.pickIndicesMajor ys
283
+ let brecOn := brecOnConst recArgInfo.indIdx
284
+ let brecOn := mkAppN brecOn indexMajorArgs
285
+ let packedFTypes ← inferArgumentTypesN positions.size brecOn
286
+ let packedFArgs ← positions.mapMwith PProdN.mkLambdas packedFTypes FArgs
287
+ let brecOn := mkAppN brecOn packedFArgs
288
+ let some (size, idx) := positions.findSome? fun pos => (pos.size, ·) <$> pos.finIdxOf? fnIdx
289
+ | throwError "mkBrecOnApp: Could not find {fnIdx} in {positions}"
290
+ let brecOn ← PProdN.projM size idx brecOn
291
+ mkLambdaFVars ys (mkAppN brecOn otherArgs)
292
+
293
+ end Lean.Elab.Structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Basic.lean ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Basic
8
+ import Lean.Meta.ForEachExpr
9
+
10
+ namespace Lean.Elab.Structural
11
+
12
+ structure State where
13
+ /-- As part of the inductive predicates case, we keep adding more and more discriminants from the
14
+ local context and build up a bigger matcher application until we reach a fixed point.
15
+ As a side-effect, this creates matchers. Here we capture all these side-effects, because
16
+ the construction rolls back any changes done to the environment and the side-effects
17
+ need to be replayed. -/
18
+ addMatchers : Array (MetaM Unit) := #[]
19
+
20
+ abbrev M := StateRefT State MetaM
21
+
22
+ instance : Inhabited (M α) where
23
+ default := throwError "failed"
24
+
25
+ def run (x : M α) (s : State := {}) : MetaM (α × State) :=
26
+ StateRefT'.run x s
27
+
28
+ /--
29
+ Return true iff `e` contains an application `recFnName .. t ..` where the term `t` is
30
+ the argument we are trying to recurse on, and it contains loose bound variables.
31
+
32
+ We use this test to decide whether we should process a matcher-application as a regular
33
+ application or not. That is, whether we should push the `below` argument should be affected by the matcher or not.
34
+ If `e` does not contain an application of the form `recFnName .. t ..`, then we know
35
+ the recursion doesn't depend on any pattern variable in this matcher.
36
+ -/
37
+ def recArgHasLooseBVarsAt (recFnName : Name) (recArgPos : Nat) (e : Expr) : Bool :=
38
+ let app? := e.find? fun e =>
39
+ e.isAppOf recFnName && e.getAppNumArgs > recArgPos && (e.getArg! recArgPos).hasLooseBVars
40
+ app?.isSome
41
+
42
+
43
+ /--
44
+ Lets say we have `n` mutually recursive functions whose recursive arguments are from a group
45
+ of `m` mutually inductive data types. This mapping does not have to be one-to-one: for one type
46
+ there can be zero, one or more functions. We use the logic in the `FunPacker` modules to combine
47
+ the bodies (and motives) of multiple such functions.
48
+
49
+ Therefore we have to take the `n` functions, group them by their recursive argument's type,
50
+ and for each such type, keep track of the order of the functions.
51
+
52
+ We represent these positions as an `Array (Array Nat)`. We have that
53
+
54
+ * `positions.size = indInfo.numTypeFormers`
55
+ * `positions.flatten` is a permutation of `[0:n]`, so each of the `n` functions has exactly one
56
+ position, and each position refers to one of the `n` functions.
57
+ * if `k ∈ positions[i]` then the recursive argument of function `k` is has type `indInfo.all[i]`
58
+ (or corresponding nested inductive type)
59
+
60
+ -/
61
+ abbrev Positions := Array (Array Nat)
62
+
63
+ /--
64
+ The number of indices in the array.
65
+ -/
66
+ def Positions.numIndices (positions : Positions) : Nat :=
67
+ positions.foldl (fun s poss => s + poss.size) 0
68
+
69
+ /--
70
+ `positions.inverse[k] = i` means that function `i` has type k
71
+ -/
72
+ def Positions.inverse (positions : Positions) : Array Nat := Id.run do
73
+ let mut r := .replicate positions.numIndices 0
74
+ for _h : i in [:positions.size] do
75
+ for k in positions[i] do
76
+ r := r.set! k i
77
+ return r
78
+
79
+ /--
80
+ Groups the `xs` by their `f` value, and puts these groups into the order given by `ys`.
81
+ -/
82
+ def Positions.groupAndSort {α β} [Inhabited α] [DecidableEq β]
83
+ (f : α → β) (xs : Array α) (ys : Array β) : Positions :=
84
+ let positions := ys.map fun y => (Array.range xs.size).filter fun i => f xs[i]! = y
85
+ -- Sanity check: is this really a grouped permutation of all the indices?
86
+ assert! Array.range xs.size == positions.flatten.qsort Nat.blt
87
+ positions
88
+
89
+ /--
90
+ Let `positions.size = ys.size` and `positions.numIndices = xs.size`. Maps `f` over each `y` in `ys`,
91
+ also passing in those elements `xs` that belong to that are those elements of `xs` that belong to
92
+ `y` according to `positions`.
93
+ -/
94
+ def Positions.mapMwith {α β m} [Monad m] [Inhabited β] (f : α → Array β → m γ)
95
+ (positions : Positions) (ys : Array α) (xs : Array β) : m (Array γ) := do
96
+ assert! positions.size = ys.size
97
+ assert! positions.numIndices = xs.size
98
+ (Array.zip ys positions).mapM fun ⟨y, poss⟩ => f y (poss.map (xs[·]!))
99
+
100
+ end Lean.Elab.Structural
101
+
102
+ builtin_initialize
103
+ Lean.registerTraceClass `Elab.definition.structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Eqns.lean ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Eqns
8
+ import Lean.Meta.Tactic.Split
9
+ import Lean.Meta.Tactic.Simp.Main
10
+ import Lean.Meta.Tactic.Apply
11
+ import Lean.Elab.PreDefinition.Basic
12
+ import Lean.Elab.PreDefinition.Eqns
13
+ import Lean.Elab.PreDefinition.FixedParams
14
+ import Lean.Elab.PreDefinition.Structural.Basic
15
+
16
+ namespace Lean.Elab
17
+ open Meta
18
+ open Eqns
19
+
20
+ namespace Structural
21
+
22
+ structure EqnInfo extends EqnInfoCore where
23
+ recArgPos : Nat
24
+ declNames : Array Name
25
+ fixedParamPerms : FixedParamPerms
26
+ deriving Inhabited
27
+
28
+ private partial def mkProof (declName : Name) (type : Expr) : MetaM Expr := do
29
+ withTraceNode `Elab.definition.structural.eqns (return m!"{exceptEmoji ·} proving:{indentExpr type}") do
30
+ withNewMCtxDepth do
31
+ let main ← mkFreshExprSyntheticOpaqueMVar type
32
+ let (_, mvarId) ← main.mvarId!.intros
33
+ unless (← tryURefl mvarId) do -- catch easy cases
34
+ go (← deltaLHS mvarId)
35
+ instantiateMVars main
36
+ where
37
+ go (mvarId : MVarId) : MetaM Unit := do
38
+ withTraceNode `Elab.definition.structural.eqns (return m!"{exceptEmoji ·} step:\n{MessageData.ofGoal mvarId}") do
39
+ if (← tryURefl mvarId) then
40
+ trace[Elab.definition.structural.eqns] "tryURefl succeeded"
41
+ return ()
42
+ else if (← tryContradiction mvarId) then
43
+ trace[Elab.definition.structural.eqns] "tryContadiction succeeded"
44
+ return ()
45
+ else if let some mvarId ← whnfReducibleLHS? mvarId then
46
+ trace[Elab.definition.structural.eqns] "whnfReducibleLHS succeeded"
47
+ go mvarId
48
+ else if let some mvarId ← simpMatch? mvarId then
49
+ trace[Elab.definition.structural.eqns] "simpMatch? succeeded"
50
+ go mvarId
51
+ else if let some mvarId ← simpIf? mvarId then
52
+ trace[Elab.definition.structural.eqns] "simpIf? succeeded"
53
+ go mvarId
54
+ else
55
+ let ctx ← Simp.mkContext
56
+ match (← simpTargetStar mvarId ctx (simprocs := {})).1 with
57
+ | TacticResultCNM.closed =>
58
+ trace[Elab.definition.structural.eqns] "simpTargetStar closed the goal"
59
+ | TacticResultCNM.modified mvarId =>
60
+ trace[Elab.definition.structural.eqns] "simpTargetStar modified the goal"
61
+ go mvarId
62
+ | TacticResultCNM.noChange =>
63
+ if let some mvarId ← deltaRHS? mvarId declName then
64
+ trace[Elab.definition.structural.eqns] "deltaRHS? succeeded"
65
+ go mvarId
66
+ else if let some mvarIds ← casesOnStuckLHS? mvarId then
67
+ trace[Elab.definition.structural.eqns] "casesOnStuckLHS? succeeded"
68
+ mvarIds.forM go
69
+ else if let some mvarIds ← splitTarget? mvarId then
70
+ trace[Elab.definition.structural.eqns] "splitTarget? succeeded"
71
+ mvarIds.forM go
72
+ else
73
+ throwError "failed to generate equational theorem for '{declName}'\n{MessageData.ofGoal mvarId}"
74
+
75
+ def mkEqns (info : EqnInfo) : MetaM (Array Name) :=
76
+ withOptions (tactic.hygienic.set · false) do
77
+ let eqnTypes ← withNewMCtxDepth <| lambdaTelescope (cleanupAnnotations := true) info.value fun xs body => do
78
+ let us := info.levelParams.map mkLevelParam
79
+ let target ← mkEq (mkAppN (Lean.mkConst info.declName us) xs) body
80
+ let goal ← mkFreshExprSyntheticOpaqueMVar target
81
+ mkEqnTypes info.declNames goal.mvarId!
82
+ let mut thmNames := #[]
83
+ for h : i in [: eqnTypes.size] do
84
+ let type := eqnTypes[i]
85
+ trace[Elab.definition.structural.eqns] "eqnType {i+1}: {type}"
86
+ let name := mkEqLikeNameFor (← getEnv) info.declName s!"{eqnThmSuffixBasePrefix}{i+1}"
87
+ thmNames := thmNames.push name
88
+ -- determinism: `type` should be independent of the environment changes since `baseName` was
89
+ -- added
90
+ realizeConst info.declNames[0]! name (doRealize name type)
91
+ return thmNames
92
+ where
93
+ doRealize name type := withOptions (tactic.hygienic.set · false) do
94
+ let value ← mkProof info.declName type
95
+ let (type, value) ← removeUnusedEqnHypotheses type value
96
+ let type ← letToHave type
97
+ addDecl <| Declaration.thmDecl {
98
+ name, type, value
99
+ levelParams := info.levelParams
100
+ }
101
+ inferDefEqAttr name
102
+
103
+ builtin_initialize eqnInfoExt : MapDeclarationExtension EqnInfo ← mkMapDeclarationExtension
104
+
105
+ def registerEqnsInfo (preDef : PreDefinition) (declNames : Array Name) (recArgPos : Nat)
106
+ (fixedParamPerms : FixedParamPerms) : CoreM Unit := do
107
+ ensureEqnReservedNamesAvailable preDef.declName
108
+ modifyEnv fun env => eqnInfoExt.insert env preDef.declName
109
+ { preDef with recArgPos, declNames, fixedParamPerms }
110
+
111
+ def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
112
+ if let some info := eqnInfoExt.find? (← getEnv) declName then
113
+ mkEqns info
114
+ else
115
+ return none
116
+
117
+ /-- Generate the "unfold" lemma for `declName`. -/
118
+ def mkUnfoldEq (declName : Name) (info : EqnInfo) : MetaM Name := do
119
+ let name := mkEqLikeNameFor (← getEnv) info.declName unfoldThmSuffix
120
+ realizeConst info.declNames[0]! name (doRealize name)
121
+ return name
122
+ where
123
+ doRealize name := withOptions (tactic.hygienic.set · false) do
124
+ lambdaTelescope info.value fun xs body => do
125
+ let us := info.levelParams.map mkLevelParam
126
+ let type ← mkEq (mkAppN (Lean.mkConst declName us) xs) body
127
+ let goal ← mkFreshExprSyntheticOpaqueMVar type
128
+ mkUnfoldProof declName goal.mvarId!
129
+ let type ← mkForallFVars xs type
130
+ let type ← letToHave type
131
+ let value ← mkLambdaFVars xs (← instantiateMVars goal)
132
+ addDecl <| Declaration.thmDecl {
133
+ name, type, value
134
+ levelParams := info.levelParams
135
+ }
136
+ inferDefEqAttr name
137
+
138
+ def getUnfoldFor? (declName : Name) : MetaM (Option Name) := do
139
+ if let some info := eqnInfoExt.find? (← getEnv) declName then
140
+ return some (← mkUnfoldEq declName info)
141
+ else
142
+ return none
143
+
144
+ @[export lean_get_structural_rec_arg_pos]
145
+ def getStructuralRecArgPosImp? (declName : Name) : CoreM (Option Nat) := do
146
+ let some info := eqnInfoExt.find? (← getEnv) declName | return none
147
+ return some info.recArgPos
148
+
149
+ builtin_initialize
150
+ registerGetEqnsFn getEqnsFor?
151
+ registerGetUnfoldEqnFn getUnfoldFor?
152
+ registerTraceClass `Elab.definition.structural.eqns
153
+
154
+ end Structural
155
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/FindRecArg.lean ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Elab.PreDefinition.TerminationMeasure
8
+ import Lean.Elab.PreDefinition.FixedParams
9
+ import Lean.Elab.PreDefinition.Structural.Basic
10
+ import Lean.Elab.PreDefinition.Structural.RecArgInfo
11
+
12
+ namespace Lean.Elab.Structural
13
+ open Meta
14
+
15
+ def prettyParam (xs : Array Expr) (i : Nat) : MetaM MessageData := do
16
+ let x := xs[i]!
17
+ let n ← x.fvarId!.getUserName
18
+ addMessageContextFull <| if n.hasMacroScopes then m!"#{i+1}" else m!"{x}"
19
+
20
+ def prettyRecArg (xs : Array Expr) (value : Expr) (recArgInfo : RecArgInfo) : MetaM MessageData := do
21
+ lambdaTelescope value fun ys _ => prettyParam (xs ++ ys) recArgInfo.recArgPos
22
+
23
+ def prettyParameterSet (fnNames : Array Name) (xs : Array Expr) (values : Array Expr)
24
+ (recArgInfos : Array RecArgInfo) : MetaM MessageData := do
25
+ if fnNames.size = 1 then
26
+ return m!"parameter " ++ (← prettyRecArg xs values[0]! recArgInfos[0]!)
27
+ else
28
+ let mut l := #[]
29
+ for fnName in fnNames, value in values, recArgInfo in recArgInfos do
30
+ l := l.push m!"{(← prettyRecArg xs value recArgInfo)} of {fnName}"
31
+ return m!"parameters " ++ .andList l.toList
32
+
33
+ private def getIndexMinPos (xs : Array Expr) (indices : Array Expr) : Nat := Id.run do
34
+ let mut minPos := xs.size
35
+ for index in indices do
36
+ match xs.idxOf? index with
37
+ | some pos => if pos < minPos then minPos := pos
38
+ | _ => pure ()
39
+ return minPos
40
+
41
+ -- Indices can only depend on other indices
42
+ private def hasBadIndexDep? (ys : Array Expr) (indices : Array Expr) : MetaM (Option (Expr × Expr)) := do
43
+ for index in indices do
44
+ let indexType ← inferType index
45
+ for y in ys do
46
+ if !indices.contains y && (← dependsOn indexType y.fvarId!) then
47
+ return some (index, y)
48
+ return none
49
+
50
+ -- Inductive datatype parameters cannot depend on ys
51
+ private def hasBadParamDep? (ys : Array Expr) (indParams : Array Expr) : MetaM (Option (Expr × Expr)) := do
52
+ for p in indParams do
53
+ for y in ys do
54
+ if ← dependsOn p y.fvarId! then
55
+ return some (p, y)
56
+ return none
57
+
58
+ /--
59
+ Assemble the `RecArgInfo` for the `i`th parameter in the parameter list `xs`. This performs
60
+ various sanity checks on the parameter (is it even of inductive type etc).
61
+ -/
62
+ def getRecArgInfo (fnName : Name) (fixedParamPerm : FixedParamPerm) (xs : Array Expr) (i : Nat) : MetaM RecArgInfo := do
63
+ assert! fixedParamPerm.size = xs.size
64
+ if h : i < xs.size then
65
+ if fixedParamPerm.isFixed i then
66
+ throwError "it is unchanged in the recursive calls"
67
+ let x := xs[i]
68
+ let localDecl ← getFVarLocalDecl x
69
+ if localDecl.isLet then
70
+ throwError "it is a let-binding"
71
+ let xType ← whnfD localDecl.type
72
+ matchConstInduct xType.getAppFn (fun _ => throwError "its type is not an inductive") fun indInfo us => do
73
+ let indArgs : Array Expr := xType.getAppArgs
74
+ let indParams : Array Expr := indArgs[*...indInfo.numParams]
75
+ let indIndices : Array Expr := indArgs[indInfo.numParams...*]
76
+ if !indIndices.all Expr.isFVar then
77
+ throwError "its type {indInfo.name} is an inductive family and indices are not variables{indentExpr xType}"
78
+ else if !indIndices.allDiff then
79
+ throwError "its type {indInfo.name} is an inductive family and indices are not pairwise distinct{indentExpr xType}"
80
+ else
81
+ let ys := fixedParamPerm.pickVarying xs
82
+ match (← hasBadIndexDep? ys indIndices) with
83
+ | some (index, y) =>
84
+ throwError "its type {indInfo.name} is an inductive family{indentExpr xType}\nand index{indentExpr index}\ndepends on the non index{indentExpr y}"
85
+ | none =>
86
+ match (← hasBadParamDep? ys indParams) with
87
+ | some (indParam, y) =>
88
+ throwError "its type is an inductive datatype{indentExpr xType}\nand the datatype parameter{indentExpr indParam}\ndepends on the function parameter{indentExpr y}\nwhich is not fixed."
89
+ | none =>
90
+ let indAll := indInfo.all.toArray
91
+ let .some indIdx := indAll.idxOf? indInfo.name | panic! "{indInfo.name} not in {indInfo.all}"
92
+ let indicesPos := indIndices.map fun index => match xs.idxOf? index with | some i => i | none => unreachable!
93
+ let indGroupInst := {
94
+ IndGroupInfo.ofInductiveVal indInfo with
95
+ levels := us
96
+ params := indParams }
97
+ return { fnName := fnName
98
+ fixedParamPerm := fixedParamPerm
99
+ recArgPos := i
100
+ indicesPos := indicesPos
101
+ indGroupInst := indGroupInst
102
+ indIdx := indIdx }
103
+ else
104
+ throwError "the index #{i+1} exceeds {xs.size}, the number of parameters"
105
+
106
+ /--
107
+ Collects the `RecArgInfos` for one function, and returns a report for why the others were not
108
+ considered.
109
+
110
+ The `xs` are the fixed parameters, `value` the body with the fixed prefix instantiated.
111
+
112
+ Takes the optional user annotation into account (`termMeasure?`). If this is given and the measure
113
+ is unsuitable, throw an error.
114
+ -/
115
+ def getRecArgInfos (fnName : Name) (fixedParamPerm : FixedParamPerm) (xs : Array Expr)
116
+ (value : Expr) (termMeasure? : Option TerminationMeasure) : MetaM (Array RecArgInfo × MessageData) := do
117
+ lambdaTelescope value fun ys _ => do
118
+ if let .some termMeasure := termMeasure? then
119
+ -- User explicitly asked to use a certain measure, so throw errors eagerly
120
+ let recArgInfo ← withRef termMeasure.ref do
121
+ prependError m!"cannot use specified measure for structural recursion:" do
122
+ let args := fixedParamPerm.buildArgs xs ys
123
+ getRecArgInfo fnName fixedParamPerm args (← termMeasure.structuralArg)
124
+ return (#[recArgInfo], m!"")
125
+ else
126
+ let args := fixedParamPerm.buildArgs xs ys
127
+ let mut recArgInfos := #[]
128
+ let mut report : MessageData := m!""
129
+ -- No `termination_by`, so try all, and remember the errors
130
+ for idx in [:args.size] do
131
+ try
132
+ let recArgInfo ← getRecArgInfo fnName fixedParamPerm args idx
133
+ recArgInfos := recArgInfos.push recArgInfo
134
+ catch e =>
135
+ report := report ++ (m!"Not considering parameter {← prettyParam args idx} of {fnName}:" ++
136
+ indentD e.toMessageData) ++ "\n"
137
+ trace[Elab.definition.structural] "getRecArgInfos report: {report}"
138
+ return (recArgInfos, report)
139
+
140
+
141
+ /--
142
+ Reorders the `RecArgInfos` of one function to put arguments that are indices of other arguments
143
+ last.
144
+ See issue #837 for an example where we can show termination using the index of an inductive family, but
145
+ we don't get the desired definitional equalities.
146
+ -/
147
+ def nonIndicesFirst (recArgInfos : Array RecArgInfo) : Array RecArgInfo := Id.run do
148
+ let mut indicesPos : Std.HashSet Nat := {}
149
+ for recArgInfo in recArgInfos do
150
+ for pos in recArgInfo.indicesPos do
151
+ indicesPos := indicesPos.insert pos
152
+ let (indices,nonIndices) := recArgInfos.partition (indicesPos.contains ·.recArgPos)
153
+ return nonIndices ++ indices
154
+
155
+ private def dedup [Monad m] (eq : α → α → m Bool) (xs : Array α) : m (Array α) := do
156
+ let mut ret := #[]
157
+ for x in xs do
158
+ unless (← ret.anyM (eq · x)) do
159
+ ret := ret.push x
160
+ return ret
161
+
162
+ /--
163
+ Given the `RecArgInfo`s of all the recursive functions, find the inductive groups to consider.
164
+ -/
165
+ def inductiveGroups (recArgInfos : Array RecArgInfo) : MetaM (Array IndGroupInst) :=
166
+ dedup IndGroupInst.isDefEq (recArgInfos.map (·.indGroupInst))
167
+
168
+ /--
169
+ Filters the `recArgInfos` by those that describe an argument that's part of the recursive inductive
170
+ group `group`.
171
+
172
+ Because of nested inductives this function has the ability to change the `recArgInfo`.
173
+ Consider
174
+ ```
175
+ inductive Tree where | node : List Tree → Tree
176
+ ```
177
+ then when we look for arguments whose type is part of the group `Tree`, we want to also consider
178
+ the argument of type `List Tree`, even though that argument’s `RecArgInfo` refers to initially to
179
+ `List`.
180
+ -/
181
+ def argsInGroup (group : IndGroupInst) (xs : Array Expr) (value : Expr)
182
+ (recArgInfos : Array RecArgInfo) : MetaM (Array RecArgInfo) := do
183
+
184
+ let nestedTypeFormers ← group.nestedTypeFormers
185
+
186
+ recArgInfos.filterMapM fun recArgInfo => do
187
+ -- Is this argument from the same mutual group of inductives?
188
+ if (← group.isDefEq recArgInfo.indGroupInst) then
189
+ return (.some recArgInfo)
190
+
191
+ -- Can this argument be understood as the auxiliary type former of a nested inductive?
192
+ if nestedTypeFormers.isEmpty then return .none
193
+ lambdaTelescope value fun ys _ => do
194
+ let x := (xs++ys)[recArgInfo.recArgPos]!
195
+ for nestedTypeFormer in nestedTypeFormers, indIdx in [group.all.size : group.numMotives] do
196
+ let xType ← whnfD (← inferType x)
197
+ let (indIndices, _, type) ← forallMetaTelescope nestedTypeFormer
198
+ if (← isDefEqGuarded type xType) then
199
+ let indIndices ← indIndices.mapM instantiateMVars
200
+ if !indIndices.all Expr.isFVar then
201
+ -- throwError "indices are not variables{indentExpr xType}"
202
+ continue
203
+ if !indIndices.allDiff then
204
+ -- throwError "indices are not pairwise distinct{indentExpr xType}"
205
+ continue
206
+ -- TODO: Do we have to worry about the indices ending up in the fixed prefix here?
207
+ if let some (_index, _y) ← hasBadIndexDep? ys indIndices then
208
+ -- throwError "its type {indInfo.name} is an inductive family{indentExpr xType}\nand index{indentExpr index}\ndepends on the non index{indentExpr y}"
209
+ continue
210
+ let indicesPos := indIndices.map fun index => match (xs++ys).idxOf? index with | some i => i | none => unreachable!
211
+ return .some
212
+ { fnName := recArgInfo.fnName
213
+ fixedParamPerm := recArgInfo.fixedParamPerm
214
+ recArgPos := recArgInfo.recArgPos
215
+ indicesPos := indicesPos
216
+ indGroupInst := group
217
+ indIdx := indIdx }
218
+ return .none
219
+
220
+ def maxCombinationSize : Nat := 10
221
+
222
+ def allCombinations (xss : Array (Array α)) : Option (Array (Array α)) :=
223
+ if xss.foldl (· * ·.size) 1 > maxCombinationSize then
224
+ none
225
+ else
226
+ let rec go i acc : Array (Array α):=
227
+ if h : i < xss.size then
228
+ xss[i].flatMap fun x => go (i + 1) (acc.push x)
229
+ else
230
+ #[acc]
231
+ some (go 0 #[])
232
+
233
+
234
+ def tryAllArgs (fnNames : Array Name) (fixedParamPerms : FixedParamPerms) (xs : Array Expr)
235
+ (values : Array Expr) (termMeasure?s : Array (Option TerminationMeasure)) (k : Array RecArgInfo → M α) : M α := do
236
+ let mut report := m!""
237
+ -- Gather information on all possible recursive arguments
238
+ let mut recArgInfoss := #[]
239
+ for fnName in fnNames, value in values, termMeasure? in termMeasure?s, fixedParamPerm in fixedParamPerms.perms do
240
+ let (recArgInfos, thisReport) ← getRecArgInfos fnName fixedParamPerm xs value termMeasure?
241
+ report := report ++ thisReport
242
+ recArgInfoss := recArgInfoss.push recArgInfos
243
+ -- Put non-indices first
244
+ recArgInfoss := recArgInfoss.map nonIndicesFirst
245
+ trace[Elab.definition.structural] "recArgInfos:{indentD (.joinSep (recArgInfoss.flatten.toList.map (repr ·)) Format.line)}"
246
+ -- Inductive groups to consider
247
+ let groups ← inductiveGroups recArgInfoss.flatten
248
+ trace[Elab.definition.structural] "inductive groups: {groups}"
249
+ if groups.isEmpty then
250
+ report := report ++ "no parameters suitable for structural recursion"
251
+ -- Consider each group
252
+ for group in groups do
253
+ -- Select those RecArgInfos that are compatible with this inductive group
254
+ let mut recArgInfoss' := #[]
255
+ for value in values, recArgInfos in recArgInfoss do
256
+ recArgInfoss' := recArgInfoss'.push (← argsInGroup group xs value recArgInfos)
257
+ if let some idx := recArgInfoss'.findIdx? (·.isEmpty) then
258
+ report := report ++ m!"Skipping arguments of type {group}, as {fnNames[idx]!} has no compatible argument.\n"
259
+ continue
260
+ if let some combs := allCombinations recArgInfoss' then
261
+ for comb in combs do
262
+ try
263
+ -- Check that the group actually has a brecOn (we used to check this in getRecArgInfo,
264
+ -- but in the first phase we do not want to rule-out non-recursive types like `Array`, which
265
+ -- are ok in a nested group. This logic can maybe simplified)
266
+ unless (← hasConst (group.brecOnName 0)) do
267
+ throwError "the type {group} does not have a `.brecOn` recursor"
268
+ let r ← k comb
269
+ trace[Elab.definition.structural] "tryAllArgs report:\n{report}"
270
+ return r
271
+ catch e =>
272
+ let m ← prettyParameterSet fnNames xs values comb
273
+ report := report ++ m!"Cannot use {m}:{indentD e.toMessageData}\n"
274
+ else
275
+ report := report ++ m!"Too many possible combinations of parameters of type {group} (or " ++
276
+ m!"please indicate the recursive argument explicitly using `termination_by structural`).\n"
277
+ report := m!"failed to infer structural recursion:\n" ++ report
278
+ trace[Elab.definition.structural] "tryAllArgs:\n{report}"
279
+ throwError report
280
+
281
+ end Lean.Elab.Structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/IndGroupInfo.lean ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Meta.InferType
8
+
9
+ /-!
10
+ This module contains the types
11
+ * `IndGroupInfo`, a variant of `InductiveVal` with information that
12
+ applies to a whole group of mutual inductives and
13
+ * `IndGroupInst` which extends `IndGroupInfo` with levels and parameters
14
+ to indicate a instantiation of the group.
15
+
16
+ One purpose of this abstraction is to make it clear when a function operates on a group as
17
+ a whole, rather than a specific inductive within the group.
18
+ -/
19
+
20
+ namespace Lean.Elab.Structural
21
+ open Lean Meta
22
+
23
+ /--
24
+ A mutually inductive group, identified by the `all` array of the `InductiveVal` of its
25
+ constituents.
26
+ -/
27
+ structure IndGroupInfo where
28
+ all : Array Name
29
+ numNested : Nat
30
+ deriving BEq, Inhabited, Repr
31
+
32
+ def IndGroupInfo.ofInductiveVal (indInfo : InductiveVal) : IndGroupInfo where
33
+ all := indInfo.all.toArray
34
+ numNested := indInfo.numNested
35
+
36
+ def IndGroupInfo.numMotives (group : IndGroupInfo) : Nat :=
37
+ group.all.size + group.numNested
38
+
39
+ /-- Instantiates the right `.brecOn` for the given type former index,
40
+ including universe parameters and fixed prefix. -/
41
+ partial def IndGroupInfo.brecOnName (info : IndGroupInfo) (idx : Nat) : Name :=
42
+ if let .some n := info.all[idx]? then
43
+ mkBRecOnName n
44
+ else
45
+ let j := idx - info.all.size + 1
46
+ info.brecOnName 0 |>.appendIndexAfter j
47
+
48
+ /--
49
+ An instance of an mutually inductive group of inductives, identified by the `all` array
50
+ and the level and expressions parameters.
51
+
52
+ For example this distinguishes between `List α` and `List β` so that we will not even attempt
53
+ mutual structural recursion on such incompatible types.
54
+ -/
55
+ structure IndGroupInst extends IndGroupInfo where
56
+ levels : List Level
57
+ params : Array Expr
58
+ deriving Inhabited, Repr
59
+
60
+ def IndGroupInst.toMessageData (igi : IndGroupInst) : MessageData :=
61
+ mkAppN (.const igi.all[0]! igi.levels) igi.params
62
+
63
+ instance : ToMessageData IndGroupInst where
64
+ toMessageData := IndGroupInst.toMessageData
65
+
66
+ def IndGroupInst.isDefEq (igi1 igi2 : IndGroupInst) : MetaM Bool := do
67
+ unless igi1.toIndGroupInfo == igi2.toIndGroupInfo do return false
68
+ unless igi1.levels.length = igi2.levels.length do return false
69
+ unless (igi1.levels.zip igi2.levels).all (fun (l₁, l₂) => Level.isEquiv l₁ l₂) do return false
70
+ unless igi1.params.size = igi2.params.size do return false
71
+ unless (← (igi1.params.zip igi2.params).allM (fun (e₁, e₂) => Meta.isDefEqGuarded e₁ e₂)) do return false
72
+ return true
73
+
74
+ /-- Instantiates the right `.brecOn` for the given type former index,
75
+ including universe parameters and fixed prefix. -/
76
+ def IndGroupInst.brecOn (group : IndGroupInst) (lvl : Level) (idx : Nat) : Expr :=
77
+ let n := group.brecOnName idx
78
+ let us := lvl :: group.levels
79
+ mkAppN (.const n us) group.params
80
+
81
+ /--
82
+ Figures out the nested type formers of an inductive group, with parameters instantiated
83
+ and indices still forall-abstracted.
84
+
85
+ For example given a nested inductive
86
+ ```
87
+ inductive Tree α where | node : α → Vector (Tree α) n → Tree α
88
+ ```
89
+ (where `n` is an index of `Vector`) and the instantiation `Tree Int` it will return
90
+ ```
91
+ #[(n : Nat) → Vector (Tree Int) n]
92
+ ```
93
+
94
+ -/
95
+ def IndGroupInst.nestedTypeFormers (igi : IndGroupInst) : MetaM (Array Expr) := do
96
+ if igi.numNested = 0 then return #[]
97
+ -- We extract this information from the motives of the recursor
98
+ let recName := mkRecName igi.all[0]!
99
+ let recInfo ← getConstInfoRec recName
100
+ assert! recInfo.numMotives = igi.numMotives
101
+ let aux := mkAppN (.const recName (0 :: igi.levels)) igi.params
102
+ let motives ← inferArgumentTypesN recInfo.numMotives aux
103
+ let auxMotives : Array Expr := motives[igi.all.size...*]
104
+ auxMotives.mapM fun motive =>
105
+ forallTelescopeReducing motive fun xs _ => do
106
+ assert! xs.size > 0
107
+ mkForallFVars xs.pop (← inferType xs.back!)
108
+
109
+ end Lean.Elab.Structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/IndPred.lean ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Dany Fabian
5
+ -/
6
+ prelude
7
+ import Lean.Meta.IndPredBelow
8
+ import Lean.Elab.PreDefinition.Basic
9
+ import Lean.Elab.PreDefinition.Structural.Basic
10
+ import Lean.Elab.PreDefinition.Structural.RecArgInfo
11
+
12
+ namespace Lean.Elab.Structural
13
+ open Meta
14
+
15
+ private def replaceIndPredRecApp (fixedParamPerm : FixedParamPerm) (funType : Expr) (e : Expr) : M Expr := do
16
+ withoutProofIrrelevance do
17
+ withTraceNode `Elab.definition.structural (fun _ => pure m!"eliminating recursive call {e}") do
18
+ -- We want to replace `e` with an expression of the same type
19
+ let main ← mkFreshExprSyntheticOpaqueMVar (← inferType e)
20
+ let args : Array Expr := e.getAppArgs
21
+ let ys := fixedParamPerm.pickVarying args
22
+ let lctx ← getLCtx
23
+ let r ← lctx.anyM fun localDecl => do
24
+ if localDecl.isAuxDecl then return false
25
+ let (mvars, _, t) ← forallMetaTelescope localDecl.type -- NB: do not reduce, we want to see the `funType`
26
+ unless t.getAppFn == funType do return false
27
+ withTraceNodeBefore `Elab.definition.structural (do pure m!"trying {mkFVar localDecl.fvarId} : {localDecl.type}") do
28
+ if ys.size < t.getAppNumArgs then
29
+ trace[Elab.definition.structural] "too few arguments, expected {t.getAppNumArgs}, found {ys.size}. Underapplied recursive call?"
30
+ return false
31
+ if (← (t.getAppArgs.zip ys).allM (fun (t,s) => isDefEq t s)) then
32
+ main.mvarId!.assign (mkAppN (mkAppN localDecl.toExpr mvars) ys[t.getAppNumArgs...*])
33
+ return ← mvars.allM fun v => do
34
+ unless (← v.mvarId!.isAssigned) do
35
+ trace[Elab.definition.structural] "Cannot use {mkFVar localDecl.fvarId}: parameter {v} remains unassigned"
36
+ return false
37
+ return true
38
+ trace[Elab.definition.structural] "Arguments do not match"
39
+ return false
40
+ unless r do
41
+ throwError "Could not eliminate recursive call {e}"
42
+ instantiateMVars main
43
+
44
+ private partial def replaceIndPredRecApps (recArgInfo : RecArgInfo) (funType : Expr) (motive : Expr) (e : Expr) : M Expr := do
45
+ let rec loop (e : Expr) : M Expr := do
46
+ match e with
47
+ | Expr.lam n d b c =>
48
+ withLocalDecl n c (← loop d) fun x => do
49
+ mkLambdaFVars #[x] (← loop (b.instantiate1 x))
50
+ | Expr.forallE n d b c =>
51
+ withLocalDecl n c (← loop d) fun x => do
52
+ mkForallFVars #[x] (← loop (b.instantiate1 x))
53
+ | Expr.letE n type val body nondep =>
54
+ mapLetDecl n (← loop type) (← loop val) (nondep := nondep) fun x => do
55
+ loop (body.instantiate1 x)
56
+ | Expr.mdata d b => do
57
+ if let some stx := getRecAppSyntax? e then
58
+ withRef stx <| loop b
59
+ else
60
+ return mkMData d (← loop b)
61
+ | Expr.proj n i e => return mkProj n i (← loop e)
62
+ | Expr.app _ _ =>
63
+ let processApp (e : Expr) : M Expr := do
64
+ e.withApp fun f args => do
65
+ if f.isConstOf recArgInfo.fnName then
66
+ replaceIndPredRecApp recArgInfo.fixedParamPerm funType e
67
+ else
68
+ return mkAppN (← loop f) (← args.mapM loop)
69
+ match (← matchMatcherApp? e) with
70
+ | some matcherApp =>
71
+ if !recArgHasLooseBVarsAt recArgInfo.fnName recArgInfo.recArgPos e then
72
+ processApp e
73
+ else
74
+ trace[Elab.definition.structural] "matcherApp before adding below transformation:\n{matcherApp.toExpr}"
75
+ let rec addBelow (matcherApp : MatcherApp) : M Expr := do
76
+ if let some (t, idx) ← IndPredBelow.findBelowIdx matcherApp.discrs motive then
77
+ let (newApp, addMatcher) ← IndPredBelow.mkBelowMatcher matcherApp motive t idx
78
+ modify fun s => { s with addMatchers := s.addMatchers.push addMatcher }
79
+ let some newApp ← matchMatcherApp? newApp | throwError "not a matcherApp: {newApp}"
80
+ addBelow newApp
81
+ else pure matcherApp.toExpr
82
+
83
+ let newApp ← addBelow matcherApp
84
+ if newApp == matcherApp.toExpr then
85
+ throwError "could not add below discriminant"
86
+ else
87
+ trace[Elab.definition.structural] "modified matcher:\n{newApp}"
88
+ processApp newApp
89
+ | none => processApp e
90
+ | e =>
91
+ ensureNoRecFn #[recArgInfo.fnName] e
92
+ pure e
93
+ loop e
94
+
95
+ /--
96
+ Transform the body of a recursive function into a non-recursive one.
97
+
98
+ The `value` is the function with (only) the fixed parameters instantiated.
99
+ -/
100
+ def mkIndPredBRecOn (recArgInfo : RecArgInfo) (value : Expr) : M Expr := do
101
+ lambdaTelescope value fun ys value => do
102
+ let type := (← inferType value).headBeta
103
+ let (indexMajorArgs, otherArgs) := recArgInfo.pickIndicesMajor ys
104
+ trace[Elab.definition.structural] "indexMajorArgs: {indexMajorArgs}, otherArgs: {otherArgs}"
105
+ let funType ← mkLambdaFVars ys type
106
+ withLetDecl `funType (← inferType funType) funType fun funType => do
107
+ let motive ← mkForallFVars otherArgs (mkAppN funType ys)
108
+ let motive ← mkLambdaFVars indexMajorArgs motive
109
+ trace[Elab.definition.structural] "brecOn motive: {motive}"
110
+ let brecOn := Lean.mkConst (mkBRecOnName recArgInfo.indName!) recArgInfo.indGroupInst.levels
111
+ let brecOn := mkAppN brecOn recArgInfo.indGroupInst.params
112
+ let brecOn := mkApp brecOn motive
113
+ let brecOn := mkAppN brecOn indexMajorArgs
114
+ check brecOn
115
+ let brecOnType ← inferType brecOn
116
+ trace[Elab.definition.structural] "brecOn {brecOn}"
117
+ trace[Elab.definition.structural] "brecOnType {brecOnType}"
118
+ -- we need to close the telescope here, because the local context is used:
119
+ -- The root cause was, that this copied code puts an ih : FType into the
120
+ -- local context and later, when we use the local context to build the recursive
121
+ -- call, it uses this ih. But that ih doesn't exist in the actual brecOn call.
122
+ -- That's why it must go.
123
+ let FType ← forallBoundedTelescope brecOnType (some 1) fun F _ => do
124
+ let F := F[0]!
125
+ let FType ← inferType F
126
+ trace[Elab.definition.structural] "FType: {FType}"
127
+ instantiateForall FType indexMajorArgs
128
+ forallBoundedTelescope FType (some 1) fun below _ => do
129
+ let below := below[0]!
130
+ let valueNew ← replaceIndPredRecApps recArgInfo funType motive value
131
+ let Farg ← mkLambdaFVars (indexMajorArgs ++ #[below] ++ otherArgs) valueNew
132
+ let brecOn := mkApp brecOn Farg
133
+ let brecOn := mkAppN brecOn otherArgs
134
+ let brecOn ← mkLetFVars #[funType] brecOn
135
+ mkLambdaFVars ys brecOn
136
+
137
+ end Lean.Elab.Structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Main.lean ADDED
@@ -0,0 +1,209 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Elab.PreDefinition.TerminationMeasure
8
+ import Lean.Elab.PreDefinition.Mutual
9
+ import Lean.Elab.PreDefinition.Structural.Basic
10
+ import Lean.Elab.PreDefinition.Structural.FindRecArg
11
+ import Lean.Elab.PreDefinition.Structural.Preprocess
12
+ import Lean.Elab.PreDefinition.Structural.BRecOn
13
+ import Lean.Elab.PreDefinition.Structural.IndPred
14
+ import Lean.Elab.PreDefinition.Structural.Eqns
15
+ import Lean.Elab.PreDefinition.Structural.SmartUnfolding
16
+ import Lean.Meta.Tactic.TryThis
17
+
18
+ namespace Lean.Elab
19
+ namespace Structural
20
+ open Meta
21
+
22
+ private def getFixedPrefix (declName : Name) (xs : Array Expr) (value : Expr) : MetaM Nat := do
23
+ let numFixedRef ← IO.mkRef xs.size
24
+ forEachExpr' value fun e => do
25
+ if e.isAppOf declName then
26
+ let args := e.getAppArgs
27
+ numFixedRef.modify fun numFixed => if args.size < numFixed then args.size else numFixed
28
+ for arg in args, x in xs do
29
+ /- We should not use structural equality here. For example, given the definition
30
+ ```
31
+ def V.map {α β} f x x_1 :=
32
+ @V.map.match_1.{1} α (fun x x_2 => V β x) x x_1
33
+ (fun x x_2 => @V.mk₁ β x (f Bool.true x_2))
34
+ (fun e => @V.mk₂ β (V.map (fun b => α b) (fun b => β b) f Bool.false e))
35
+ ```
36
+ The first three arguments at `V.map (fun b => α b) (fun b => β b) f Bool.false e` are "fixed"
37
+ modulo definitional equality.
38
+
39
+ We disable to proof irrelevance to be able to use structural recursion on inductive predicates.
40
+ For example, consider the example
41
+ ```
42
+ inductive PList (α : Type) : Prop
43
+ | nil
44
+ | cons : α → PList α → PList α
45
+
46
+ infixr:67 " ::: " => PList.cons
47
+
48
+ set_option trace.Elab.definition.structural true in
49
+ def pmap {α β} (f : α → β) : PList α → PList β
50
+ | PList.nil => PList.nil
51
+ | a:::as => f a ::: pmap f as
52
+ ```
53
+ The "Fixed" prefix would be 4 since all elements of type `PList α` are definitionally equal.
54
+ -/
55
+ if !(← withoutProofIrrelevance <| withReducible <| isDefEq arg x) then
56
+ -- We continue searching if e's arguments are not a prefix of `xs`
57
+ return true
58
+ return false
59
+ else
60
+ return true
61
+ numFixedRef.get
62
+
63
+ partial def withCommonTelescope (preDefs : Array PreDefinition) (k : Array Expr → Array Expr → M α) : M α :=
64
+ go #[] (preDefs.map (·.value))
65
+ where
66
+ go (fvars : Array Expr) (vals : Array Expr) : M α := do
67
+ if !(vals.all fun val => val.isLambda) then
68
+ k fvars vals
69
+ else if !(← vals.allM fun val=> isDefEq val.bindingDomain! vals[0]!.bindingDomain!) then
70
+ k fvars vals
71
+ else
72
+ withLocalDecl vals[0]!.bindingName! vals[0]!.binderInfo vals[0]!.bindingDomain! fun x =>
73
+ go (fvars.push x) (vals.map fun val => val.bindingBody!.instantiate1 x)
74
+
75
+ private def elimMutualRecursion (preDefs : Array PreDefinition) (fixedParamPerms : FixedParamPerms)
76
+ (xs : Array Expr) (recArgInfos : Array RecArgInfo) : M (Array PreDefinition) := do
77
+ let values ← preDefs.mapIdxM (fixedParamPerms.perms[·]!.instantiateLambda ·.value xs)
78
+ let indInfo ← getConstInfoInduct recArgInfos[0]!.indGroupInst.all[0]!
79
+ if ← isInductivePredicate indInfo.name then
80
+ -- Here we branch off to the IndPred construction, but only for non-mutual functions
81
+ unless preDefs.size = 1 do
82
+ throwError "structural mutual recursion over inductive predicates is not supported"
83
+ trace[Elab.definition.structural] "Using mkIndPred construction"
84
+ let preDef := preDefs[0]!
85
+ let recArgInfo := recArgInfos[0]!
86
+ let value := values[0]!
87
+ let valueNew ← mkIndPredBRecOn recArgInfo value
88
+ let valueNew ← lambdaTelescope value fun ys _ => do
89
+ mkLambdaFVars (etaReduce := true) (fixedParamPerms.perms[0]!.buildArgs xs ys) (mkAppN valueNew ys)
90
+ trace[Elab.definition.structural] "Nonrecursive value:{indentExpr valueNew}"
91
+ check valueNew
92
+ return #[{ preDef with value := valueNew }]
93
+
94
+ -- Groups the (indices of the) definitions by their position in indInfo.all
95
+ let positions : Positions := .groupAndSort (·.indIdx) recArgInfos (Array.range indInfo.numTypeFormers)
96
+ trace[Elab.definition.structural] "assignments of type formers of {indInfo.name} to functions: {positions}"
97
+
98
+ -- Construct the common `.brecOn` arguments
99
+ let motives ← (Array.zip recArgInfos values).mapM fun (r, v) => mkBRecOnMotive r v
100
+ trace[Elab.definition.structural] "motives: {motives}"
101
+ let brecOnConst ← mkBRecOnConst recArgInfos positions motives
102
+ let FTypes ← inferBRecOnFTypes recArgInfos positions brecOnConst
103
+ trace[Elab.definition.structural] "FTypes: {FTypes}"
104
+ let FArgs ← (recArgInfos.zip (values.zip FTypes)).mapM fun (r, (v, t)) =>
105
+ mkBRecOnF recArgInfos positions r v t
106
+ trace[Elab.definition.structural] "FArgs: {FArgs}"
107
+ -- Assemble the individual `.brecOn` applications
108
+ let valuesNew ← (Array.zip recArgInfos values).mapIdxM fun i (r, v) =>
109
+ mkBrecOnApp positions i brecOnConst FArgs r v
110
+ -- Abstract over the fixed prefixed, preserving the original parameter order
111
+ let valuesNew ← (values.zip valuesNew).mapIdxM fun i ⟨value, valueNew⟩ =>
112
+ lambdaTelescope value fun ys _ => do
113
+ -- NB: Do not eta-contract here, other code (e.g. FunInd) expects this to have the
114
+ -- same number of head lambdas as the original definition
115
+ mkLambdaFVars (fixedParamPerms.perms[i]!.buildArgs xs ys) (valueNew.beta ys)
116
+ return (Array.zip preDefs valuesNew).map fun ⟨preDef, valueNew⟩ => { preDef with value := valueNew }
117
+
118
+ private def inferRecArgPos (preDefs : Array PreDefinition) (termMeasure?s : Array (Option TerminationMeasure)) :
119
+ M (Array Nat × (Array PreDefinition) × FixedParamPerms) := do
120
+ withoutModifyingEnv do
121
+ preDefs.forM (addAsAxiom ·)
122
+ let fnNames := preDefs.map (·.declName)
123
+ let preDefs ← preDefs.mapM fun preDef =>
124
+ return { preDef with value := (← preprocess preDef.value fnNames) }
125
+
126
+ -- The syntactically fixed arguments
127
+ let fixedParamPerms ← getFixedParamPerms preDefs
128
+
129
+ fixedParamPerms.perms[0]!.forallTelescope preDefs[0]!.type fun xs => do
130
+ let values ← preDefs.mapIdxM (fixedParamPerms.perms[·]!.instantiateLambda ·.value xs)
131
+
132
+ tryAllArgs fnNames fixedParamPerms xs values termMeasure?s fun recArgInfos => do
133
+ let recArgPoss := recArgInfos.map (·.recArgPos)
134
+ trace[Elab.definition.structural] "Trying argument set {recArgPoss}"
135
+ let (fixedParamPerms', xs', toErase) := fixedParamPerms.erase xs (recArgInfos.map (·.indicesAndRecArgPos))
136
+ -- We may have to turn some fixed parameters into varying parameters
137
+ let recArgInfos := recArgInfos.mapIdx fun i recArgInfo =>
138
+ {recArgInfo with fixedParamPerm := fixedParamPerms'.perms[i]!}
139
+ if xs'.size != xs.size then
140
+ trace[Elab.definition.structural] "Reduced fixed params from {xs} to {xs'}, erasing {toErase.map mkFVar}"
141
+ trace[Elab.definition.structural] "New recArgInfos {repr recArgInfos}"
142
+ -- Check that the parameters of the IndGroupInsts are still fine
143
+ for recArgInfo in recArgInfos do
144
+ for indParam in recArgInfo.indGroupInst.params do
145
+ for y in toErase do
146
+ if (← dependsOn indParam y) then
147
+ if indParam.isFVarOf y then
148
+ throwError "its type is an inductive datatype and the datatype parameter\
149
+ {indentExpr indParam}\n\
150
+ which cannot be fixed as it is an index or depends on an index, and indices \
151
+ cannot be fixed parameters when using structural recursion."
152
+ else
153
+ throwError "its type is an inductive datatype and the datatype parameter\
154
+ {indentExpr indParam}\ndepends on the function parameter{indentExpr (mkFVar y)}\n\
155
+ which cannot be fixed as it is an index or depends on an index, and indices \
156
+ cannot be fixed parameters when using structural recursion."
157
+ withErasedFVars toErase do
158
+ let preDefs' ← elimMutualRecursion preDefs fixedParamPerms' xs' recArgInfos
159
+ return (recArgPoss, preDefs', fixedParamPerms')
160
+
161
+ def reporttermMeasure (preDef : PreDefinition) (recArgPos : Nat) : MetaM Unit := do
162
+ if let some ref := preDef.termination.terminationBy?? then
163
+ let fn ← lambdaTelescope preDef.value fun xs _ => mkLambdaFVars xs xs[recArgPos]!
164
+ let termMeasure : TerminationMeasure:= {ref := .missing, structural := true, fn}
165
+ let arity ← lambdaTelescope preDef.value fun xs _ => pure xs.size
166
+ let stx ← termMeasure.delab arity (extraParams := preDef.termination.extraParams)
167
+ Tactic.TryThis.addSuggestion ref stx
168
+
169
+
170
+ def structuralRecursion (preDefs : Array PreDefinition) (termMeasure?s : Array (Option TerminationMeasure)) : TermElabM Unit := do
171
+ let names := preDefs.map (·.declName)
172
+ let ((recArgPoss, preDefsNonRec, fixedParamPerms), state) ← run <| inferRecArgPos preDefs termMeasure?s
173
+ for recArgPos in recArgPoss, preDef in preDefs do
174
+ reporttermMeasure preDef recArgPos
175
+ state.addMatchers.forM liftM
176
+ preDefsNonRec.forM fun preDefNonRec => do
177
+ let preDefNonRec ← eraseRecAppSyntax preDefNonRec
178
+ prependError m!"structural recursion failed, produced type incorrect term" do
179
+ -- We create the `_unsafe_rec` before we abstract nested proofs.
180
+ -- Reason: the nested proofs may be referring to the _unsafe_rec.
181
+ addNonRec preDefNonRec (applyAttrAfterCompilation := false) (all := names.toList)
182
+ let preDefs ← preDefs.mapM (eraseRecAppSyntax ·)
183
+ addAndCompilePartialRec preDefs
184
+ for preDef in preDefs, recArgPos in recArgPoss do
185
+ let mut preDef := preDef
186
+ unless preDef.kind.isTheorem do
187
+ unless (← isProp preDef.type) do
188
+ preDef ← abstractNestedProofs preDef
189
+ /-
190
+ Don't save predefinition info for equation generator
191
+ for theorems and definitions that are propositions.
192
+ See issue #2327
193
+ -/
194
+ registerEqnsInfo preDef (preDefs.map (·.declName)) recArgPos fixedParamPerms
195
+ addSmartUnfoldingDef preDef recArgPos
196
+ markAsRecursive preDef.declName
197
+ for preDef in preDefs do
198
+ -- must happen in separate loop so realizations can see eqnInfos of all other preDefs
199
+ enableRealizationsForConst preDef.declName
200
+ -- must happen after `enableRealizationsForConst`
201
+ generateEagerEqns preDef.declName
202
+ applyAttributesOf preDefsNonRec AttributeApplicationTime.afterCompilation
203
+
204
+
205
+ end Structural
206
+
207
+ export Structural (structuralRecursion)
208
+
209
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Preprocess.lean ADDED
@@ -0,0 +1,53 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Transform
8
+ import Lean.Elab.RecAppSyntax
9
+
10
+ namespace Lean.Elab.Structural
11
+ open Meta
12
+
13
+ private def shouldBetaReduce (e : Expr) (recFnNames : Array Name) : Bool :=
14
+ if e.isHeadBetaTarget then
15
+ e.getAppFn.find? (fun e => e.isConst && recFnNames.contains e.constName!) |>.isSome
16
+ else
17
+ false
18
+
19
+ /--
20
+ Preprocesses the expressions to improve the effectiveness of `elimRecursion`.
21
+
22
+ * Beta reduce terms where the recursive function occurs in the lambda term.
23
+ Example:
24
+ ```
25
+ def f : Nat → Nat
26
+ | 0 => 1
27
+ | i+1 => (fun x => f x) i
28
+ ```
29
+
30
+ * Floats out the RecApp markers.
31
+ Example:
32
+ ```
33
+ def f : Nat → Nat
34
+ | 0 => 1
35
+ | i+1 => (f x) i
36
+ ```
37
+ -/
38
+ def preprocess (e : Expr) (recFnNames : Array Name) : CoreM Expr :=
39
+ Core.transform e
40
+ (pre := fun e =>
41
+ if shouldBetaReduce e recFnNames then
42
+ return .visit e.headBeta
43
+ else
44
+ return .continue)
45
+ (post := fun e => do
46
+ if e.isApp && e.getAppFn.isMData then
47
+ let .mdata m f := e.getAppFn | unreachable!
48
+ if m.isRecApp then
49
+ return .done (.mdata m (f.beta e.getAppArgs))
50
+ return .continue)
51
+
52
+
53
+ end Lean.Elab.Structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/RecArgInfo.lean ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Joachim Breitner
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Basic
8
+ import Lean.Meta.ForEachExpr
9
+ import Lean.Elab.PreDefinition.FixedParams
10
+ import Lean.Elab.PreDefinition.Structural.IndGroupInfo
11
+
12
+ namespace Lean.Elab.Structural
13
+
14
+
15
+ /--
16
+ Information about the argument of interest of a structurally recursive function.
17
+
18
+ The `Expr`s in this data structure expect the fixed parameters to be in scope, but not the other
19
+ parameters of the function. This ensures that this data structure makes sense in the other functions
20
+ of a mutually recursive group.
21
+ -/
22
+ structure RecArgInfo where
23
+ /-- the name of the recursive function -/
24
+ fnName : Name
25
+ /-- Information which arguments are fixed -/
26
+ fixedParamPerm : FixedParamPerm
27
+ /-- position of the argument we are recursing on, among all parameters -/
28
+ recArgPos : Nat
29
+ /-- position of the indices of the inductive datatype we are recursing on, among all parameters -/
30
+ indicesPos : Array Nat
31
+ /-- The inductive group (with parameters) of the argument's type -/
32
+ indGroupInst : IndGroupInst
33
+ /--
34
+ index of the inductive datatype of the argument we are recursing on.
35
+ If `< indAll.all`, a normal data type, else an auxiliary data type due to nested recursion
36
+ -/
37
+ indIdx : Nat
38
+ deriving Inhabited, Repr
39
+
40
+ /-- position of the argument and its indices we are recursing on, among all parameters -/
41
+ def RecArgInfo.indicesAndRecArgPos (info : RecArgInfo) : Array Nat :=
42
+ info.indicesPos.push info.recArgPos
43
+
44
+ /--
45
+ If `xs` are the varying parameters of the functions, partitions them into indices and major
46
+ arguments, and other parameters.
47
+ -/
48
+ def RecArgInfo.pickIndicesMajor (info : RecArgInfo) (xs : Array Expr) : (Array Expr × Array Expr) := Id.run do
49
+ -- To simplify the index calculation, pad xs with dummy values where fixed parameters are
50
+ let xs := info.fixedParamPerm.buildArgs (.replicate info.fixedParamPerm.numFixed (mkSort 0)) xs
51
+ -- First indices and major arg, using the order they appear in `info.indicesPos`
52
+ let mut indexMajorArgs := #[]
53
+ let indexMajorPos := info.indicesPos.push info.recArgPos
54
+ for j in indexMajorPos do
55
+ indexMajorArgs := indexMajorArgs.push xs[j]!
56
+ -- Then the other arguments, in the order they appear in `xs`
57
+ let mut otherVaryingArgs := #[]
58
+ for h : i in [:xs.size] do
59
+ unless indexMajorPos.contains i do
60
+ unless info.fixedParamPerm.isFixed i do
61
+ otherVaryingArgs := otherVaryingArgs.push xs[i]
62
+ return (indexMajorArgs, otherVaryingArgs)
63
+
64
+ /--
65
+ Name of the recursive data type. Assumes that it is not one of the auxiliary ones.
66
+ -/
67
+ def RecArgInfo.indName! (info : RecArgInfo) : Name :=
68
+ info.indGroupInst.all[info.indIdx]!
69
+
70
+ end Lean.Elab.Structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/SmartUnfolding.lean ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.PreDefinition.Basic
8
+ import Lean.Elab.PreDefinition.Structural.Basic
9
+ import Lean.Meta.Match.MatcherApp.Basic
10
+
11
+ namespace Lean.Elab.Structural
12
+ open Meta
13
+
14
+ partial def addSmartUnfoldingDefAux (preDef : PreDefinition) (recArgPos : Nat) : MetaM PreDefinition := do
15
+ return { preDef with
16
+ declName := mkSmartUnfoldingNameFor preDef.declName
17
+ value := (← visit preDef.value)
18
+ modifiers := default
19
+ }
20
+ where
21
+ /--
22
+ Auxiliary method for annotating `match`-alternatives with `markSmartUnfoldingMatch` and `markSmartUnfoldingMatchAlt`.
23
+
24
+ It uses the following approach:
25
+ - Whenever it finds a `match` application `e` s.t. `recArgHasLooseBVarsAt preDef.declName recArgPos e`,
26
+ it marks the `match` with `markSmartUnfoldingMatch`, and each alternative that does not contain a nested marked `match`
27
+ is marked with `markSmartUnfoldingMatchAlt`.
28
+
29
+ Recall that the condition `recArgHasLooseBVarsAt preDef.declName recArgPos e` is the one used at `mkBRecOn`.
30
+ -/
31
+ visit (e : Expr) : MetaM Expr := do
32
+ match e with
33
+ | Expr.lam .. => lambdaTelescope e fun xs b => do mkLambdaFVars xs (← visit b)
34
+ | Expr.forallE .. => forallTelescope e fun xs b => do mkForallFVars xs (← visit b)
35
+ | Expr.letE n type val body nondep =>
36
+ mapLetDecl n type (← visit val) (nondep := nondep) fun x => do
37
+ visit (body.instantiate1 x)
38
+ | Expr.mdata d b => return mkMData d (← visit b)
39
+ | Expr.proj n i s => return mkProj n i (← visit s)
40
+ | Expr.app .. =>
41
+ let processApp (e : Expr) : MetaM Expr :=
42
+ e.withApp fun f args =>
43
+ return mkAppN (← visit f) (← args.mapM visit)
44
+ match (← matchMatcherApp? e) with
45
+ | some matcherApp =>
46
+ if !recArgHasLooseBVarsAt preDef.declName recArgPos e then
47
+ processApp e
48
+ else
49
+ let mut altsNew := #[]
50
+ for alt in matcherApp.alts, numParams in matcherApp.altNumParams do
51
+ let altNew ← lambdaBoundedTelescope alt numParams fun xs altBody => do
52
+ unless xs.size = numParams do
53
+ throwError "unexpected matcher application alternative{indentExpr alt}\nat application{indentExpr e}"
54
+ let altBody ← visit altBody
55
+ let containsSUnfoldMatch := Option.isSome <| altBody.find? fun e => smartUnfoldingMatch? e |>.isSome
56
+ let altBody := if !containsSUnfoldMatch then markSmartUnfoldingMatchAlt altBody else altBody
57
+ mkLambdaFVars xs altBody
58
+ altsNew := altsNew.push altNew
59
+ return markSmartUnfoldingMatch { matcherApp with alts := altsNew }.toExpr
60
+ | _ => processApp e
61
+ | _ => return e
62
+
63
+ partial def addSmartUnfoldingDef (preDef : PreDefinition) (recArgPos : Nat) : TermElabM Unit := do
64
+ if (← isProp preDef.type) then
65
+ return ()
66
+ else
67
+ withEnableInfoTree false do
68
+ let preDefSUnfold ← addSmartUnfoldingDefAux preDef recArgPos
69
+ addNonRec preDefSUnfold (cleanupValue := true)
70
+
71
+ end Lean.Elab.Structural
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/WF/Basic.lean ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Joachim Breitner
5
+ -/
6
+
7
+ prelude
8
+ import Lean.Elab.Tactic.Basic
9
+
10
+ namespace Lean.Elab.WF
11
+
12
+ register_builtin_option debug.rawDecreasingByGoal : Bool := {
13
+ defValue := false
14
+ descr := "Shows the raw `decreasing_by` goal including internal implementation detail \
15
+ instead of cleaning it up with the `clean_wf` tactic. Can be enabled for debugging \
16
+ purposes. Please report an issue if you have to use this option for other reasons."
17
+ }
18
+
19
+ open Lean Elab Tactic
20
+
21
+ def applyCleanWfTactic : TacticM Unit := do
22
+ unless debug.rawDecreasingByGoal.get (← getOptions) do
23
+ Tactic.evalTactic (← `(tactic| all_goals clean_wf))
24
+
25
+ end Lean.Elab.WF
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/WF/Eqns.lean ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Tactic.Rewrite
8
+ import Lean.Meta.Tactic.Split
9
+ import Lean.Elab.PreDefinition.Basic
10
+ import Lean.Elab.PreDefinition.Eqns
11
+ import Lean.Meta.ArgsPacker.Basic
12
+ import Lean.Elab.PreDefinition.WF.Unfold
13
+ import Lean.Elab.PreDefinition.FixedParams
14
+ import Init.Data.Array.Basic
15
+
16
+ namespace Lean.Elab.WF
17
+ open Meta
18
+ open Eqns
19
+
20
+ structure EqnInfo extends EqnInfoCore where
21
+ declNames : Array Name
22
+ declNameNonRec : Name
23
+ argsPacker : ArgsPacker
24
+ fixedParamPerms : FixedParamPerms
25
+ deriving Inhabited
26
+
27
+ builtin_initialize eqnInfoExt : MapDeclarationExtension EqnInfo ← mkMapDeclarationExtension
28
+
29
+ def registerEqnsInfo (preDefs : Array PreDefinition) (declNameNonRec : Name) (fixedParamPerms : FixedParamPerms)
30
+ (argsPacker : ArgsPacker) : MetaM Unit := do
31
+ preDefs.forM fun preDef => ensureEqnReservedNamesAvailable preDef.declName
32
+ /-
33
+ See issue #2327.
34
+ Remark: we could do better for mutual declarations that mix theorems and definitions. However, this is a rare
35
+ combination, and we would have add support for it in the equation generator. I did not check which assumptions are made there.
36
+ -/
37
+ unless preDefs.all fun p => p.kind.isTheorem do
38
+ unless (← preDefs.allM fun p => isProp p.type) do
39
+ let declNames := preDefs.map (·.declName)
40
+ modifyEnv fun env =>
41
+ preDefs.foldl (init := env) fun env preDef =>
42
+ eqnInfoExt.insert env preDef.declName { preDef with
43
+ declNames, declNameNonRec, argsPacker, fixedParamPerms }
44
+
45
+ def getEqnsFor? (declName : Name) : MetaM (Option (Array Name)) := do
46
+ if let some info := eqnInfoExt.find? (← getEnv) declName then
47
+ mkEqns declName info.declNames (tryRefl := false)
48
+ else
49
+ return none
50
+
51
+ builtin_initialize
52
+ registerGetEqnsFn getEqnsFor?
53
+
54
+
55
+ /--
56
+ This is a hack to fix fallout from #8519, where a non-exposed wfrec definition `foo`
57
+ in a module would cause `foo.eq_def` to be defined eagerly and privately,
58
+ but it should still be visible from non-mudule files.
59
+
60
+ So we create a unfold equation generator that aliases an existing private `eq_def` to
61
+ wherever the current module expects it.
62
+ -/
63
+ def copyPrivateUnfoldTheorem : GetUnfoldEqnFn := fun declName => do
64
+ withTraceNode `ReservedNameAction (pure m!"{exceptOptionEmoji ·} copyPrivateUnfoldTheorem running for {declName}") do
65
+ let name := mkEqLikeNameFor (← getEnv) declName unfoldThmSuffix
66
+ if let some mod ← findModuleOf? declName then
67
+ let unfoldName' := mkPrivateNameCore mod (.str declName unfoldThmSuffix)
68
+ if let some (.thmInfo info) := (← getEnv).find? unfoldName' then
69
+ realizeConst declName name do
70
+ addDecl <| Declaration.thmDecl {
71
+ name,
72
+ type := info.type,
73
+ value := .const unfoldName' (info.levelParams.map mkLevelParam),
74
+ levelParams := info.levelParams
75
+ }
76
+ return name
77
+ return none
78
+
79
+ builtin_initialize
80
+ registerGetUnfoldEqnFn copyPrivateUnfoldTheorem
81
+
82
+ end Lean.Elab.WF
backend/core/leanprover--lean4---v4.22.0/src/lean/Std/Data/HashMap/Lemmas.lean ADDED
The diff for this file is too large to render. See raw diff