Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +10 -0
- MyProject/.lake/build/bin/myproject.exe +3 -0
- MyProject/.lake/build/ir/Main.c.o.noexport.hash +1 -0
- MyProject/.lake/build/ir/Main.c.o.noexport.trace +17 -0
- MyProject/.lake/build/ir/Main.setup.json +6 -0
- MyProject/.lake/build/ir/MyProject.c +33 -0
- MyProject/.lake/build/ir/MyProject.c.hash +1 -0
- MyProject/.lake/build/ir/MyProject.c.o.noexport +0 -0
- MyProject/.lake/build/ir/MyProject.c.o.noexport.hash +1 -0
- MyProject/.lake/build/ir/MyProject.c.o.noexport.trace +17 -0
- MyProject/.lake/build/ir/MyProject.setup.json +6 -0
- MyProject/.lake/build/ir/MyProject/Basic.c +51 -0
- MyProject/.lake/build/ir/MyProject/Basic.c.hash +1 -0
- MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport +0 -0
- MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport.hash +1 -0
- MyProject/.lake/build/ir/MyProject/Basic.c.o.noexport.trace +17 -0
- MyProject/.lake/build/ir/MyProject/Basic.setup.json +6 -0
- MyProject/.lake/build/lib/lean/Main.ilean +1 -0
- MyProject/.lake/build/lib/lean/Main.ilean.hash +1 -0
- MyProject/.lake/build/lib/lean/Main.olean +0 -0
- MyProject/.lake/build/lib/lean/Main.olean.hash +1 -0
- MyProject/.lake/build/lib/lean/Main.trace +30 -0
- MyProject/.lake/build/lib/lean/MyProject.ilean +1 -0
- MyProject/.lake/build/lib/lean/MyProject.ilean.hash +1 -0
- MyProject/.lake/build/lib/lean/MyProject.olean +0 -0
- MyProject/.lake/build/lib/lean/MyProject.olean.hash +1 -0
- MyProject/.lake/build/lib/lean/MyProject.trace +30 -0
- MyProject/.lake/build/lib/lean/MyProject/Basic.ilean +1 -0
- MyProject/.lake/build/lib/lean/MyProject/Basic.ilean.hash +1 -0
- MyProject/.lake/build/lib/lean/MyProject/Basic.olean +0 -0
- MyProject/.lake/build/lib/lean/MyProject/Basic.olean.hash +1 -0
- MyProject/.lake/build/lib/lean/MyProject/Basic.trace +26 -0
- MyProject/MyProject/Basic.lean +1 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Nonrec/Eqns.lean +56 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Eqns.lean +124 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Induction.lean +402 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/PartialFixpoint/Main.lean +224 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/BRecOn.lean +293 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Basic.lean +103 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Eqns.lean +155 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/FindRecArg.lean +281 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/IndGroupInfo.lean +109 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/IndPred.lean +137 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Main.lean +209 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/Preprocess.lean +53 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/RecArgInfo.lean +70 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/Structural/SmartUnfolding.lean +71 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/WF/Basic.lean +25 -0
- backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/PreDefinition/WF/Eqns.lean +82 -0
- 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
|
|
|