mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-06 04:04:06 +00:00
Compare commits
752 Commits
split_issu
...
CheckAssig
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03bae7b676 | ||
|
|
a993934839 | ||
|
|
aa3c87b2c7 | ||
|
|
869e42b7c3 | ||
|
|
bdbadbd74b | ||
|
|
3120c3d8f8 | ||
|
|
e1cbae26cc | ||
|
|
9009c1ac91 | ||
|
|
5c61ad38be | ||
|
|
44985dc9a6 | ||
|
|
3dfa7812f9 | ||
|
|
2dd6b2b9c8 | ||
|
|
6d0b00885e | ||
|
|
75c0373c1a | ||
|
|
b37df8e31a | ||
|
|
da9c68a37a | ||
|
|
6fce7b82bc | ||
|
|
f220efc5ba | ||
|
|
613dbf1637 | ||
|
|
8e68c5d44e | ||
|
|
9ce15fb0c6 | ||
|
|
0dc317c73c | ||
|
|
44366382d3 | ||
|
|
095c7b2bfc | ||
|
|
c4e4248487 | ||
|
|
9ef996259b | ||
|
|
30fa18816c | ||
|
|
94fd406c04 | ||
|
|
3411935e53 | ||
|
|
b518091bd4 | ||
|
|
a58a09056f | ||
|
|
c45a6a93f9 | ||
|
|
f917f811c8 | ||
|
|
3c687df6d5 | ||
|
|
45475d6434 | ||
|
|
c6feffa2bd | ||
|
|
b54a9ec9b9 | ||
|
|
68bb92a35a | ||
|
|
dcdbb9b411 | ||
|
|
dd22447afd | ||
|
|
f0b0c60e0f | ||
|
|
9305049f1e | ||
|
|
852ee1683f | ||
|
|
4c9db2fab8 | ||
|
|
70c1e5690d | ||
|
|
5d84aebeb9 | ||
|
|
7e5d1103c2 | ||
|
|
2d9cbdb450 | ||
|
|
fcdecacc4f | ||
|
|
c9c2c8720a | ||
|
|
703658391e | ||
|
|
8898c8eaa9 | ||
|
|
2d89693b71 | ||
|
|
c3655b626e | ||
|
|
644a12744b | ||
|
|
92b271ee64 | ||
|
|
24f550fd6f | ||
|
|
cee84286e6 | ||
|
|
75781b46f5 | ||
|
|
ea97aac83b | ||
|
|
b1ebe7b484 | ||
|
|
07013da720 | ||
|
|
2bc87298d9 | ||
|
|
390a9a63a2 | ||
|
|
6d4ec153ad | ||
|
|
bf304769e0 | ||
|
|
7488b27b0d | ||
|
|
33d24c3bca | ||
|
|
f71a1fb4ae | ||
|
|
01ec8c5e14 | ||
|
|
d975e4302e | ||
|
|
74715a0f9c | ||
|
|
d540ba787a | ||
|
|
b33d08078d | ||
|
|
e9025bdf79 | ||
|
|
5651a11ac8 | ||
|
|
481894e95d | ||
|
|
7213583c8d | ||
|
|
6a473e67aa | ||
|
|
e5d44f4033 | ||
|
|
c78bb62c51 | ||
|
|
e620cf3c80 | ||
|
|
edecf3d4ba | ||
|
|
1c73983dcf | ||
|
|
4b7b69c20a | ||
|
|
87d361d9b6 | ||
|
|
a3ae75f847 | ||
|
|
0a8d1bf808 | ||
|
|
a58da122b9 | ||
|
|
3b1af163eb | ||
|
|
0e823710e3 | ||
|
|
c38d271283 | ||
|
|
4dbd20343f | ||
|
|
0203cb091d | ||
|
|
f6ce866e39 | ||
|
|
95549f17da | ||
|
|
15c6ac2076 | ||
|
|
4aa74d9c0b | ||
|
|
efbecf272d | ||
|
|
78146190e5 | ||
|
|
b4db495f98 | ||
|
|
9f47e08ecc | ||
|
|
728980443f | ||
|
|
ca945be133 | ||
|
|
f2573dc51e | ||
|
|
51f01d8c8a | ||
|
|
b486c6748b | ||
|
|
38288ae07a | ||
|
|
b939fef2cf | ||
|
|
eb15c08ea0 | ||
|
|
72f2e7aab1 | ||
|
|
cd21687884 | ||
|
|
a08ef5ffa2 | ||
|
|
53e6e99a29 | ||
|
|
59ca274296 | ||
|
|
ac4927de46 | ||
|
|
0ecbcfdcc3 | ||
|
|
4d4d485c19 | ||
|
|
d1174e10e6 | ||
|
|
a43356591c | ||
|
|
082ed944d8 | ||
|
|
36d71f8253 | ||
|
|
3c07e48a33 | ||
|
|
8a6eec0047 | ||
|
|
213a7221f6 | ||
|
|
42fcfcbad6 | ||
|
|
2ba7c995a6 | ||
|
|
7e72f9ab85 | ||
|
|
326dbd1e15 | ||
|
|
6bc98af67b | ||
|
|
f883fc0db6 | ||
|
|
20a7fe89b5 | ||
|
|
ac64cfd70a | ||
|
|
958ad2b54b | ||
|
|
bd5f8ef242 | ||
|
|
337db03717 | ||
|
|
3efd0e4e1f | ||
|
|
8c96d213f3 | ||
|
|
154385fdb9 | ||
|
|
9e39dc8100 | ||
|
|
dcadfd1c89 | ||
|
|
7c5d8661f4 | ||
|
|
bff30fe98e | ||
|
|
ac2dabdedf | ||
|
|
7283e2c14e | ||
|
|
f500af99e8 | ||
|
|
861ef27503 | ||
|
|
11be29e68c | ||
|
|
74f9dea701 | ||
|
|
041b80a4f5 | ||
|
|
5bc6496a7c | ||
|
|
f3e7b455bb | ||
|
|
7cd406f335 | ||
|
|
ecb35795eb | ||
|
|
dc3eccdf26 | ||
|
|
c237c1f9fb | ||
|
|
dd4e26f247 | ||
|
|
c5114c971a | ||
|
|
adc799584c | ||
|
|
bbb448cdf6 | ||
|
|
9d0302e749 | ||
|
|
8d12dd87a4 | ||
|
|
da9d44df2d | ||
|
|
5c182bd540 | ||
|
|
ecd3aa4b5d | ||
|
|
12ca422d86 | ||
|
|
0a7af630a5 | ||
|
|
fc5615880e | ||
|
|
23d898c86b | ||
|
|
dfe493d9d8 | ||
|
|
759ece7f9e | ||
|
|
89c3079072 | ||
|
|
37f9063c3e | ||
|
|
8364c3e178 | ||
|
|
215b4a6a8d | ||
|
|
7d7447563d | ||
|
|
2436562d57 | ||
|
|
4236d8a85b | ||
|
|
5f31e938c1 | ||
|
|
95bf6793aa | ||
|
|
30cf3bb3bf | ||
|
|
238885436b | ||
|
|
30a52b794a | ||
|
|
5da9038fb4 | ||
|
|
3a588e7547 | ||
|
|
9f76cb9aa5 | ||
|
|
88a7f5c592 | ||
|
|
dd6ed124ba | ||
|
|
6dd502321f | ||
|
|
bcbd7299e9 | ||
|
|
b144107ed5 | ||
|
|
c24d2186fc | ||
|
|
7ef2d2fea2 | ||
|
|
7776852d22 | ||
|
|
63c4de5fea | ||
|
|
3b14642c42 | ||
|
|
d52da36e68 | ||
|
|
bf82965eec | ||
|
|
4bac74c4ac | ||
|
|
8b9d27de31 | ||
|
|
d15f0335a9 | ||
|
|
240ebff549 | ||
|
|
a29bca7f00 | ||
|
|
313f6b3c74 | ||
|
|
43fa46412d | ||
|
|
234704e304 | ||
|
|
12a714a6f9 | ||
|
|
cdc7ed0224 | ||
|
|
217abdf97a | ||
|
|
490a2b4bf9 | ||
|
|
84d45deb10 | ||
|
|
f46d216e18 | ||
|
|
cc42a17931 | ||
|
|
e106be19dd | ||
|
|
1efd6657d4 | ||
|
|
473b34561d | ||
|
|
574066b30b | ||
|
|
1e6d617aad | ||
|
|
c17a4ddc94 | ||
|
|
5be4f5e30c | ||
|
|
3c5ac9496f | ||
|
|
6c1f8a8a63 | ||
|
|
7bea3c1508 | ||
|
|
a27d4a9519 | ||
|
|
4a2fb6e922 | ||
|
|
b7db82894b | ||
|
|
35e1554ef7 | ||
|
|
14d59b3599 | ||
|
|
a8e480cd52 | ||
|
|
d07239d1bd | ||
|
|
590de785cc | ||
|
|
d671d0d61a | ||
|
|
8e476e9d22 | ||
|
|
a3d144a362 | ||
|
|
87d41e6326 | ||
|
|
d6cb2432c6 | ||
|
|
c0ffc85d75 | ||
|
|
f62359acc7 | ||
|
|
2d09c96caf | ||
|
|
21b4377d36 | ||
|
|
1e9d96be22 | ||
|
|
647a5e9492 | ||
|
|
9c4028aab4 | ||
|
|
2c002718e0 | ||
|
|
b07384acbb | ||
|
|
efc99b982e | ||
|
|
ee430b6c80 | ||
|
|
a8740f5ed9 | ||
|
|
5e6a3cf5f9 | ||
|
|
0ed1cf7244 | ||
|
|
e83f78d5af | ||
|
|
32b9de8c77 | ||
|
|
a856016b9d | ||
|
|
c517688f1d | ||
|
|
db594425bf | ||
|
|
dcea47db02 | ||
|
|
f869902a4b | ||
|
|
d5a8c9647f | ||
|
|
d19bab0c27 | ||
|
|
6a4159c4a7 | ||
|
|
8acdafd5b3 | ||
|
|
688da9d8a7 | ||
|
|
d5e7dbad80 | ||
|
|
82f48740dc | ||
|
|
a827759f1d | ||
|
|
a4015ca36c | ||
|
|
81719f94c9 | ||
|
|
afe0b5a013 | ||
|
|
90dab5e267 | ||
|
|
6a904f2c85 | ||
|
|
2c396d6424 | ||
|
|
69f86d6478 | ||
|
|
4ea55687a5 | ||
|
|
69c71f6476 | ||
|
|
7f128b39e7 | ||
|
|
a845a007ac | ||
|
|
abf4206e9c | ||
|
|
83ad82162f | ||
|
|
93ac635a89 | ||
|
|
642c28cdbb | ||
|
|
a04f3cab5a | ||
|
|
86af04cc08 | ||
|
|
7253ef8751 | ||
|
|
f830fc9f4d | ||
|
|
671ce7afd3 | ||
|
|
87c92a3f87 | ||
|
|
15bf41cd67 | ||
|
|
906bc583c5 | ||
|
|
ea43ebd54a | ||
|
|
bb9c9bd99f | ||
|
|
fe5894f2f6 | ||
|
|
3ecbf4ae2d | ||
|
|
9b342efb84 | ||
|
|
c02aa98c6a | ||
|
|
18ba5f24e1 | ||
|
|
cbe39dc4bb | ||
|
|
a5b8d5b486 | ||
|
|
895391b73f | ||
|
|
e280de00b6 | ||
|
|
8c87a90cea | ||
|
|
54c22efca1 | ||
|
|
d4f2db9559 | ||
|
|
39e0b41fe1 | ||
|
|
84f8871c3f | ||
|
|
93fa9c8837 | ||
|
|
0768ad4eb9 | ||
|
|
c545e7b0c9 | ||
|
|
7b3c64fc85 | ||
|
|
af0b563099 | ||
|
|
af40e61811 | ||
|
|
1758b37a71 | ||
|
|
3701bee777 | ||
|
|
6d971827e2 | ||
|
|
871c9b4164 | ||
|
|
ee6737ab4d | ||
|
|
7d60d8b563 | ||
|
|
a4673e20a5 | ||
|
|
b2ee8c240d | ||
|
|
5d632a97b8 | ||
|
|
5938dbbd14 | ||
|
|
852add3e55 | ||
|
|
20c857147c | ||
|
|
9f1eb479b0 | ||
|
|
92cca5ed1b | ||
|
|
3a4d2cded3 | ||
|
|
22ae04f3e7 | ||
|
|
99f362979b | ||
|
|
3a309f7691 | ||
|
|
8f0631ab1f | ||
|
|
08acf5a136 | ||
|
|
bdfaa00b1e | ||
|
|
8ceb24a5e6 | ||
|
|
201749ccac | ||
|
|
d0bc4e4245 | ||
|
|
c2117d75a6 | ||
|
|
3477b0e7f6 | ||
|
|
696f70bb4e | ||
|
|
726e162527 | ||
|
|
de5e07c4d2 | ||
|
|
327986e6fb | ||
|
|
6c33b9c57f | ||
|
|
d907771fdd | ||
|
|
5c3360200e | ||
|
|
204d4839fa | ||
|
|
e32f3e8140 | ||
|
|
7d2155943c | ||
|
|
78c4d6daff | ||
|
|
5526ff6320 | ||
|
|
bfca7ec72a | ||
|
|
9208b3585f | ||
|
|
a94805ff71 | ||
|
|
4eb842560c | ||
|
|
490d16c80d | ||
|
|
f60721bfbd | ||
|
|
a5ecdd0a17 | ||
|
|
be717f03ef | ||
|
|
41b4914836 | ||
|
|
933445608c | ||
|
|
8e396068e4 | ||
|
|
c1df7564ce | ||
|
|
ba3565f441 | ||
|
|
af03af5037 | ||
|
|
f6666fe266 | ||
|
|
c580684c22 | ||
|
|
1a12f63f74 | ||
|
|
95b8095fa6 | ||
|
|
94cc8eb863 | ||
|
|
1cf47bce5a | ||
|
|
b73fe04710 | ||
|
|
f986a2e9ef | ||
|
|
1a9cbc96f1 | ||
|
|
7aec6c9ae7 | ||
|
|
31de2494fb | ||
|
|
d679591880 | ||
|
|
f167cfba71 | ||
|
|
180c6aaa5e | ||
|
|
ab0241dac8 | ||
|
|
dc65f03c41 | ||
|
|
de96b6d8a7 | ||
|
|
3ab2c714ec | ||
|
|
f99427bd1a | ||
|
|
1118978cbb | ||
|
|
4ea8c5ad8d | ||
|
|
a6ae49c3ab | ||
|
|
2ad6d397f8 | ||
|
|
891824bc51 | ||
|
|
f35c562ef8 | ||
|
|
bcd8517307 | ||
|
|
ce73bbe277 | ||
|
|
f0eab4b7b1 | ||
|
|
5f70c1ca64 | ||
|
|
fce82eba40 | ||
|
|
9d14e4423c | ||
|
|
0c7859a7dd | ||
|
|
c01e003b49 | ||
|
|
ce8a130724 | ||
|
|
3c18d151a6 | ||
|
|
0f48e926eb | ||
|
|
850964999e | ||
|
|
57b8b32c72 | ||
|
|
bd2aefee01 | ||
|
|
74dcd6c2a9 | ||
|
|
23b893f778 | ||
|
|
1e02c08111 | ||
|
|
0f6a802314 | ||
|
|
be197cd431 | ||
|
|
f531f4e5db | ||
|
|
8229b28cc9 | ||
|
|
582d6e7f71 | ||
|
|
4daa29e71d | ||
|
|
9124426c55 | ||
|
|
cb0755bac0 | ||
|
|
4b32d9b9a1 | ||
|
|
7602265923 | ||
|
|
6ba5704e00 | ||
|
|
98ee789990 | ||
|
|
e08a562c48 | ||
|
|
84c40d9999 | ||
|
|
aecebaab74 | ||
|
|
3b3901b824 | ||
|
|
811c1e3685 | ||
|
|
27e85cc947 | ||
|
|
9a852595c4 | ||
|
|
1311e36a98 | ||
|
|
db7a01d126 | ||
|
|
4d2f2d7cc5 | ||
|
|
f6265e25f4 | ||
|
|
d6c6e16254 | ||
|
|
818b9d7de0 | ||
|
|
34e6579190 | ||
|
|
2b0ed751bd | ||
|
|
6ed26dcf8f | ||
|
|
955135b3f9 | ||
|
|
f36bbc8d56 | ||
|
|
64eeba726a | ||
|
|
4ed79472af | ||
|
|
55d09a39b4 | ||
|
|
7de0c58dc1 | ||
|
|
04fefdd728 | ||
|
|
75fe520562 | ||
|
|
3e0ea762b8 | ||
|
|
5ce886cf96 | ||
|
|
5ad5c2cf04 | ||
|
|
d4e141e233 | ||
|
|
05f78939f6 | ||
|
|
7b965f3f18 | ||
|
|
0594bc4e5a | ||
|
|
3fb7f632a5 | ||
|
|
f6deaa8fb2 | ||
|
|
15a41ffc1c | ||
|
|
cc5c95f377 | ||
|
|
62c5bc5d0d | ||
|
|
c2edae92c8 | ||
|
|
7ef95cd30b | ||
|
|
2cd2364974 | ||
|
|
f5fd962a25 | ||
|
|
d72fcb6b2a | ||
|
|
a2a73e9611 | ||
|
|
3f2cf8bf27 | ||
|
|
d39c4d6a1c | ||
|
|
b28cfb9336 | ||
|
|
6080e3dd5c | ||
|
|
8959b2ca87 | ||
|
|
554e723433 | ||
|
|
9cc1164305 | ||
|
|
0c6f83eb6d | ||
|
|
1225b0f651 | ||
|
|
75e11ecf7c | ||
|
|
4055aecba2 | ||
|
|
1681b2fa67 | ||
|
|
c97f958ecf | ||
|
|
e2dc85274b | ||
|
|
e12999bcf6 | ||
|
|
7a0fe6f54c | ||
|
|
4a2210b7e6 | ||
|
|
e9d2f8f5f2 | ||
|
|
d5a45dfa8b | ||
|
|
fb0c46a011 | ||
|
|
0635b277ec | ||
|
|
087054172c | ||
|
|
7f00767b1e | ||
|
|
be54ccd246 | ||
|
|
4d0b7cf66c | ||
|
|
0629eebc09 | ||
|
|
9248ada3a8 | ||
|
|
144a3d9463 | ||
|
|
a7bbe7416b | ||
|
|
f31d4dc128 | ||
|
|
fb97275dcb | ||
|
|
d4d7c72365 | ||
|
|
93c9ae7c20 | ||
|
|
b8dd51500f | ||
|
|
bd091f119b | ||
|
|
d8e719f9ab | ||
|
|
93d2ad5fa7 | ||
|
|
7b56eb20a0 | ||
|
|
30a922a7e9 | ||
|
|
294f7fbec5 | ||
|
|
f3cb8a6c2d | ||
|
|
5c978a2e24 | ||
|
|
ee42c3ca56 | ||
|
|
18c97926a1 | ||
|
|
ea22ef4485 | ||
|
|
62b6e58789 | ||
|
|
714dc6d2bb | ||
|
|
5e7d2c34dc | ||
|
|
fb6d29e260 | ||
|
|
4964ce3ce8 | ||
|
|
230f335702 | ||
|
|
875e4b1904 | ||
|
|
49249b9107 | ||
|
|
3b67e15827 | ||
|
|
e3578c2f36 | ||
|
|
0f416c6a83 | ||
|
|
5178c4b6da | ||
|
|
bc6188a70a | ||
|
|
33f7865bbb | ||
|
|
968aff403b | ||
|
|
1076ca1ead | ||
|
|
43a9c73556 | ||
|
|
a92e9c7944 | ||
|
|
378b02921d | ||
|
|
5426a5c8b3 | ||
|
|
d7da45cbe6 | ||
|
|
24d51b90cc | ||
|
|
0d529e18a6 | ||
|
|
4808eb7c4b | ||
|
|
5767a597d4 | ||
|
|
e665a0d716 | ||
|
|
073b2cfc83 | ||
|
|
84e46162b5 | ||
|
|
a1a245df40 | ||
|
|
07ee719761 | ||
|
|
ee9996ec89 | ||
|
|
d2ae678fbf | ||
|
|
2a00d6cf70 | ||
|
|
d020a9c5a6 | ||
|
|
301a89aba4 | ||
|
|
f32780d863 | ||
|
|
d6eab393f4 | ||
|
|
1f732bb3b7 | ||
|
|
7d7f378e02 | ||
|
|
95db616cb6 | ||
|
|
45c5d009d6 | ||
|
|
458835360f | ||
|
|
3e05b0641b | ||
|
|
53be53f5ae | ||
|
|
dac1dacc5b | ||
|
|
d3a7569c97 | ||
|
|
49f058cb76 | ||
|
|
bc047b8530 | ||
|
|
c7c50a8bec | ||
|
|
de269060d1 | ||
|
|
e8f768f9fd | ||
|
|
0783d0fcbe | ||
|
|
2518105bd9 | ||
|
|
9096d6fc71 | ||
|
|
0a1a855ba8 | ||
|
|
c4718a87ab | ||
|
|
357b52928f | ||
|
|
bd45c0cd04 | ||
|
|
f9952e8c39 | ||
|
|
1b5b91cccf | ||
|
|
74f1373706 | ||
|
|
c87205bc9b | ||
|
|
294b1d5839 | ||
|
|
167771923e | ||
|
|
eb67654ae6 | ||
|
|
6a8cb7ffa0 | ||
|
|
face4cef75 | ||
|
|
6cad341764 | ||
|
|
2995e74133 | ||
|
|
d768f46ba6 | ||
|
|
97588301e1 | ||
|
|
fca87da2d4 | ||
|
|
3c4d6ba864 | ||
|
|
2c83e080f7 | ||
|
|
8f023b85c5 | ||
|
|
06731f99d4 | ||
|
|
59a09fb4e7 | ||
|
|
42c4a770c2 | ||
|
|
d334e96275 | ||
|
|
e9caf40493 | ||
|
|
a09726bb94 | ||
|
|
1cf71e54cf | ||
|
|
2efcbfe803 | ||
|
|
03d01f4024 | ||
|
|
f237fb67eb | ||
|
|
e10a37d80d | ||
|
|
fe0cb97c5d | ||
|
|
c96797eb93 | ||
|
|
4798c8418c | ||
|
|
456ed44550 | ||
|
|
237f392cc1 | ||
|
|
5eb5fa49cf | ||
|
|
5d2403535a | ||
|
|
2cf478cbbe | ||
|
|
b096e7d5f2 | ||
|
|
1835dd123d | ||
|
|
db74ee9e83 | ||
|
|
285a313078 | ||
|
|
8fef03d1cc | ||
|
|
749bf9c279 | ||
|
|
7b971b90c5 | ||
|
|
3119fd0240 | ||
|
|
16cad2b45c | ||
|
|
6d265b42b1 | ||
|
|
c5120c1d0d | ||
|
|
37f8b0390d | ||
|
|
bd3b466f2f | ||
|
|
f3274d375a | ||
|
|
a8de4b3b06 | ||
|
|
8d3be96024 | ||
|
|
bedcbfcfee | ||
|
|
ce6ebd1044 | ||
|
|
ab73ac9d15 | ||
|
|
3bd39ed8b6 | ||
|
|
5f9dedfe5e | ||
|
|
2a2b276ede | ||
|
|
ec775df6cc | ||
|
|
c8e668a9ad | ||
|
|
a1c8a941f0 | ||
|
|
6a7bed94d3 | ||
|
|
366f3ac272 | ||
|
|
ea46bf2839 | ||
|
|
adfd438164 | ||
|
|
748eab9511 | ||
|
|
fd4281a636 | ||
|
|
2d05ff8a48 | ||
|
|
b02c1c56ab | ||
|
|
73348fb083 | ||
|
|
18264ae62e | ||
|
|
7b72458392 | ||
|
|
bfcaaa3d9d | ||
|
|
0768b508e6 | ||
|
|
d644b377bb | ||
|
|
d85d3d5f3a | ||
|
|
745d77b068 | ||
|
|
63739a42f3 | ||
|
|
a99007ac75 | ||
|
|
b9bfd30514 | ||
|
|
0a0f1d7cc7 | ||
|
|
ba97928fbf | ||
|
|
287d46e1f6 | ||
|
|
0d30517dca | ||
|
|
faea7f98c1 | ||
|
|
ff0d338dd2 | ||
|
|
56adfb856d | ||
|
|
9c079a42e1 | ||
|
|
9d47377bda | ||
|
|
e33c32fb00 | ||
|
|
42f12967a6 | ||
|
|
5cd9f805b7 | ||
|
|
f0a11b8864 | ||
|
|
5a25612434 | ||
|
|
37d60fd2ec | ||
|
|
fbb3055f82 | ||
|
|
644c1d4e36 | ||
|
|
46db59d1d9 | ||
|
|
c53a350a9e | ||
|
|
8f507b1008 | ||
|
|
28b8778218 | ||
|
|
982c338b45 | ||
|
|
ce67d6ef9e | ||
|
|
1d6fe34b29 | ||
|
|
5924c5aea9 | ||
|
|
612bdee68c | ||
|
|
28cf1cf5cf | ||
|
|
2ae762eb75 | ||
|
|
8437d1f660 | ||
|
|
d45952e386 | ||
|
|
9d46961236 | ||
|
|
e47d84e37a | ||
|
|
05ea3ac19f | ||
|
|
a54fa7cae6 | ||
|
|
f65e3ae985 | ||
|
|
81f5b07215 | ||
|
|
9a597aeb2e | ||
|
|
ff116dae5f | ||
|
|
0dff5701af | ||
|
|
299cb9a806 | ||
|
|
b53a74d6fd | ||
|
|
007b423006 | ||
|
|
6c63c9c716 | ||
|
|
8bbb015a97 | ||
|
|
9133470243 | ||
|
|
d07b316804 | ||
|
|
ec59e7a2c0 | ||
|
|
cc33c39cb0 | ||
|
|
8c7364ee64 | ||
|
|
26b6718422 | ||
|
|
66777670e8 | ||
|
|
f05a82799a | ||
|
|
8eee5ff27f | ||
|
|
fe17b82096 | ||
|
|
def00d3920 | ||
|
|
cd16975946 | ||
|
|
0448e3f4ea | ||
|
|
d3ee0be908 | ||
|
|
d1a96f6d8f | ||
|
|
b0c1112471 | ||
|
|
e5e5a4d2e0 | ||
|
|
e020f3d159 | ||
|
|
811bad16e1 | ||
|
|
67338bac23 | ||
|
|
ba629545cc | ||
|
|
dfb496a271 | ||
|
|
250994166c | ||
|
|
73a0c73c7c | ||
|
|
258cc28dfc | ||
|
|
f61a64d2ff | ||
|
|
d984030c6a | ||
|
|
93758cc222 | ||
|
|
4fa3b3c4a0 | ||
|
|
2bc41d8f3a | ||
|
|
f97a7d4234 | ||
|
|
23a202b6be | ||
|
|
ff37e5d512 | ||
|
|
c2b8a1e618 | ||
|
|
8ca00918fb | ||
|
|
6155513c60 | ||
|
|
d6709eb157 | ||
|
|
e6be8b90f5 | ||
|
|
82401938cf | ||
|
|
3de60bb1f6 | ||
|
|
8c03650359 | ||
|
|
2faa81d41f | ||
|
|
097a4d5b6b | ||
|
|
f512826b9a | ||
|
|
7c053259d3 | ||
|
|
f3ccd6b023 | ||
|
|
7ece5d56e3 | ||
|
|
a7338c5ad8 | ||
|
|
b278f9dd30 | ||
|
|
f0471a519b | ||
|
|
42215cc072 | ||
|
|
f53b778c0d | ||
|
|
72b345c621 | ||
|
|
6171070deb | ||
|
|
7c5249278e | ||
|
|
239ade80dc | ||
|
|
47c8e340d6 | ||
|
|
c8b72beb4d | ||
|
|
9803c5dd63 | ||
|
|
d66d00dece | ||
|
|
9fde33a09f | ||
|
|
b639d102d1 | ||
|
|
02b6fb3f41 | ||
|
|
9f6bbfa106 | ||
|
|
1ff0e7a2f2 | ||
|
|
3cb6eb0ae6 | ||
|
|
489d2d11ec |
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: actionlint
|
- name: actionlint
|
||||||
uses: raven-actions/actionlint@v1
|
uses: raven-actions/actionlint@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
498
.github/workflows/ci.yml
vendored
498
.github/workflows/ci.yml
vendored
@@ -9,6 +9,17 @@ on:
|
|||||||
merge_group:
|
merge_group:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 7 * * *' # 8AM CET/11PM PT
|
- cron: '0 7 * * *' # 8AM CET/11PM PT
|
||||||
|
# for manual re-release of a nightly
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
action:
|
||||||
|
description: 'Action'
|
||||||
|
required: true
|
||||||
|
default: 'release nightly'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- release nightly
|
||||||
|
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}
|
||||||
@@ -20,8 +31,10 @@ jobs:
|
|||||||
configure:
|
configure:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
outputs:
|
outputs:
|
||||||
# Should we run only a quick CI? Yes on a pull request without the full-ci label
|
# 0: PRs without special label
|
||||||
quick: ${{ steps.set-quick.outputs.quick }}
|
# 1: PRs with `merge-ci` label, merge queue checks, master commits
|
||||||
|
# 2: PRs with `release-ci` label, releases (incl. nightlies)
|
||||||
|
check-level: ${{ steps.set-level.outputs.check-level }}
|
||||||
# The build matrix, dynamically generated here
|
# The build matrix, dynamically generated here
|
||||||
matrix: ${{ steps.set-matrix.outputs.result }}
|
matrix: ${{ steps.set-matrix.outputs.result }}
|
||||||
# Should we make a nightly release? If so, this output contains the lean version string, else it is empty
|
# Should we make a nightly release? If so, this output contains the lean version string, else it is empty
|
||||||
@@ -38,173 +51,12 @@ jobs:
|
|||||||
RELEASE_TAG: ${{ steps.set-release.outputs.RELEASE_TAG }}
|
RELEASE_TAG: ${{ steps.set-release.outputs.RELEASE_TAG }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Run quick CI?
|
|
||||||
id: set-quick
|
|
||||||
# We do not use github.event.pull_request.labels.*.name here because
|
|
||||||
# re-running a run does not update that list, and we do want to be able to
|
|
||||||
# rerun the workflow run after settings the `full-ci` label.
|
|
||||||
run: |
|
|
||||||
if [ "${{ github.event_name }}" == 'pull_request' ]
|
|
||||||
then
|
|
||||||
echo "quick=$(gh api repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }} --jq '.labels | any(.name == "full-ci") | not')" >> "$GITHUB_OUTPUT"
|
|
||||||
else
|
|
||||||
echo "quick=false" >> "$GITHUB_OUTPUT"
|
|
||||||
fi
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ github.token }}
|
|
||||||
|
|
||||||
- name: Configure build matrix
|
|
||||||
id: set-matrix
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: |
|
|
||||||
const quick = ${{ steps.set-quick.outputs.quick }};
|
|
||||||
console.log(`quick: ${quick}`);
|
|
||||||
// use large runners outside PRs where available (original repo)
|
|
||||||
// disabled for now as this mostly just speeds up the test suite which is not a bottleneck
|
|
||||||
// let large = ${{ github.event_name != 'pull_request' && github.repository == 'leanprover/lean4' }} ? "-large" : "";
|
|
||||||
let matrix = [
|
|
||||||
{
|
|
||||||
// portable release build: use channel with older glibc (2.27)
|
|
||||||
"name": "Linux LLVM",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
"release": false,
|
|
||||||
"quick": false,
|
|
||||||
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
|
|
||||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
|
|
||||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
|
||||||
"binary-check": "ldd -v",
|
|
||||||
// foreign code may be linked against more recent glibc
|
|
||||||
// reverse-ffi needs to be updated to link to LLVM libraries
|
|
||||||
"CTEST_OPTIONS": "-E 'foreign|leanlaketest_reverse-ffi'",
|
|
||||||
"CMAKE_OPTIONS": "-DLLVM=ON -DLLVM_CONFIG=${GITHUB_WORKSPACE}/build/llvm-host/bin/llvm-config"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Linux release",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
"release": true,
|
|
||||||
"quick": true,
|
|
||||||
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
|
|
||||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
|
|
||||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
|
||||||
"binary-check": "ldd -v",
|
|
||||||
// foreign code may be linked against more recent glibc
|
|
||||||
"CTEST_OPTIONS": "-E 'foreign'"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Linux",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
"check-stage3": true,
|
|
||||||
"test-speedcenter": true,
|
|
||||||
"quick": false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Linux Debug",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
"quick": false,
|
|
||||||
"CMAKE_OPTIONS": "-DCMAKE_BUILD_TYPE=Debug",
|
|
||||||
// exclude seriously slow tests
|
|
||||||
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
|
|
||||||
},
|
|
||||||
// TODO: suddenly started failing in CI
|
|
||||||
/*{
|
|
||||||
"name": "Linux fsanitize",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
"quick": false,
|
|
||||||
// turn off custom allocator & symbolic functions to make LSAN do its magic
|
|
||||||
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-fsanitize=address,undefined -DLEANC_EXTRA_FLAGS='-fsanitize=address,undefined -fsanitize-link-c++-runtime' -DSMALL_ALLOCATOR=OFF -DBSYMBOLIC=OFF",
|
|
||||||
// exclude seriously slow/problematic tests (laketests crash)
|
|
||||||
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
|
|
||||||
},*/
|
|
||||||
{
|
|
||||||
"name": "macOS",
|
|
||||||
"os": "macos-13",
|
|
||||||
"release": true,
|
|
||||||
"quick": false,
|
|
||||||
"shell": "bash -euxo pipefail {0}",
|
|
||||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst",
|
|
||||||
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
|
||||||
"binary-check": "otool -L",
|
|
||||||
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "macOS aarch64",
|
|
||||||
"os": "macos-13",
|
|
||||||
"release": true,
|
|
||||||
"quick": false,
|
|
||||||
"cross": true,
|
|
||||||
"cross_target": "aarch64-apple-darwin",
|
|
||||||
"shell": "bash -euxo pipefail {0}",
|
|
||||||
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
|
|
||||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-apple-darwin.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst",
|
|
||||||
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm-aarch64-* lean-llvm-x86_64-*",
|
|
||||||
"binary-check": "otool -L",
|
|
||||||
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Windows",
|
|
||||||
"os": "windows-2022",
|
|
||||||
"release": true,
|
|
||||||
"quick": false,
|
|
||||||
"shell": "msys2 {0}",
|
|
||||||
"CMAKE_OPTIONS": "-G \"Unix Makefiles\" -DUSE_GMP=OFF",
|
|
||||||
// for reasons unknown, interactivetests are flaky on Windows
|
|
||||||
"CTEST_OPTIONS": "--repeat until-pass:2",
|
|
||||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
|
|
||||||
"prepare-llvm": "../script/prepare-llvm-mingw.sh lean-llvm*",
|
|
||||||
"binary-check": "ldd"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Linux aarch64",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64",
|
|
||||||
"release": true,
|
|
||||||
"quick": false,
|
|
||||||
"cross": true,
|
|
||||||
"cross_target": "aarch64-unknown-linux-gnu",
|
|
||||||
"shell": "nix develop .#oldGlibcAArch -c bash -euxo pipefail {0}",
|
|
||||||
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst",
|
|
||||||
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm-aarch64-* lean-llvm-x86_64-*"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Linux 32bit",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
// Use 32bit on stage0 and stage1 to keep oleans compatible
|
|
||||||
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86",
|
|
||||||
"cmultilib": true,
|
|
||||||
"release": true,
|
|
||||||
"quick": false,
|
|
||||||
"cross": true,
|
|
||||||
"shell": "bash -euxo pipefail {0}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Web Assembly",
|
|
||||||
"os": "ubuntu-latest",
|
|
||||||
// Build a native 32bit binary in stage0 and use it to compile the oleans and the wasm build
|
|
||||||
"CMAKE_OPTIONS": "-DCMAKE_C_COMPILER_WORKS=1 -DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_CMAKE_CXX_COMPILER=clang++ -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_EXECUTABLE_SUFFIX=\"\" -DUSE_GMP=OFF -DMMAP=OFF -DSTAGE0_MMAP=OFF -DCMAKE_AR=../emsdk/emsdk-main/upstream/emscripten/emar -DCMAKE_TOOLCHAIN_FILE=../emsdk/emsdk-main/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DLEAN_INSTALL_SUFFIX=-linux_wasm32",
|
|
||||||
"wasm": true,
|
|
||||||
"cmultilib": true,
|
|
||||||
"release": true,
|
|
||||||
"quick": false,
|
|
||||||
"cross": true,
|
|
||||||
"shell": "bash -euxo pipefail {0}",
|
|
||||||
// Just a few selected tests because wasm is slow
|
|
||||||
"CTEST_OPTIONS": "-R \"leantest_1007\\.lean|leantest_Format\\.lean|leanruntest\\_1037.lean|leanruntest_ac_rfl\\.lean\""
|
|
||||||
}
|
|
||||||
];
|
|
||||||
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`)
|
|
||||||
if (quick) {
|
|
||||||
return matrix.filter((job) => job.quick)
|
|
||||||
} else {
|
|
||||||
return matrix
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
# don't schedule nightlies on forks
|
# don't schedule nightlies on forks
|
||||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4'
|
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||||
- name: Set Nightly
|
- name: Set Nightly
|
||||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4'
|
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||||
id: set-nightly
|
id: set-nightly
|
||||||
run: |
|
run: |
|
||||||
if [[ -n '${{ secrets.PUSH_NIGHTLY_TOKEN }}' ]]; then
|
if [[ -n '${{ secrets.PUSH_NIGHTLY_TOKEN }}' ]]; then
|
||||||
@@ -249,6 +101,168 @@ jobs:
|
|||||||
echo "Tag ${TAG_NAME} did not match SemVer regex."
|
echo "Tag ${TAG_NAME} did not match SemVer regex."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Set check level
|
||||||
|
id: set-level
|
||||||
|
# We do not use github.event.pull_request.labels.*.name here because
|
||||||
|
# re-running a run does not update that list, and we do want to be able to
|
||||||
|
# rerun the workflow run after setting the `release-ci`/`merge-ci` labels.
|
||||||
|
run: |
|
||||||
|
check_level=0
|
||||||
|
|
||||||
|
if [[ -n "${{ steps.set-nightly.outputs.nightly }}" || -n "${{ steps.set-release.outputs.RELEASE_TAG }}" ]]; then
|
||||||
|
check_level=2
|
||||||
|
elif [[ "${{ github.event_name }}" != "pull_request" ]]; then
|
||||||
|
check_level=1
|
||||||
|
else
|
||||||
|
labels="$(gh api repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}) --jq '.labels'"
|
||||||
|
if echo "$labels" | grep -q "release-ci"; then
|
||||||
|
check_level=2
|
||||||
|
elif echo "$labels" | grep -q "merge-ci"; then
|
||||||
|
check_level=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "check-level=$check_level" >> "$GITHUB_OUTPUT"
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
|
- name: Configure build matrix
|
||||||
|
id: set-matrix
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const level = ${{ steps.set-level.outputs.check-level }};
|
||||||
|
console.log(`level: ${level}`);
|
||||||
|
// use large runners where available (original repo)
|
||||||
|
let large = ${{ github.repository == 'leanprover/lean4' }};
|
||||||
|
let matrix = [
|
||||||
|
{
|
||||||
|
// portable release build: use channel with older glibc (2.27)
|
||||||
|
"name": "Linux LLVM",
|
||||||
|
"os": "ubuntu-latest",
|
||||||
|
"release": false,
|
||||||
|
"check-level": 2,
|
||||||
|
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
|
||||||
|
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
|
||||||
|
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
||||||
|
"binary-check": "ldd -v",
|
||||||
|
// foreign code may be linked against more recent glibc
|
||||||
|
// reverse-ffi needs to be updated to link to LLVM libraries
|
||||||
|
"CTEST_OPTIONS": "-E 'foreign|leanlaketest_reverse-ffi'",
|
||||||
|
"CMAKE_OPTIONS": "-DLLVM=ON -DLLVM_CONFIG=${GITHUB_WORKSPACE}/build/llvm-host/bin/llvm-config"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Linux release",
|
||||||
|
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||||
|
"release": true,
|
||||||
|
"check-level": 0,
|
||||||
|
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
|
||||||
|
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
|
||||||
|
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
|
||||||
|
"binary-check": "ldd -v",
|
||||||
|
// foreign code may be linked against more recent glibc
|
||||||
|
"CTEST_OPTIONS": "-E 'foreign'"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
|
||||||
|
"check-stage3": level >= 2,
|
||||||
|
"test-speedcenter": level >= 2,
|
||||||
|
"check-level": 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Linux Debug",
|
||||||
|
"os": "ubuntu-latest",
|
||||||
|
"check-level": 2,
|
||||||
|
"CMAKE_PRESET": "debug",
|
||||||
|
// exclude seriously slow tests
|
||||||
|
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest|bv_bitblast_stress'"
|
||||||
|
},
|
||||||
|
// TODO: suddenly started failing in CI
|
||||||
|
/*{
|
||||||
|
"name": "Linux fsanitize",
|
||||||
|
"os": "ubuntu-latest",
|
||||||
|
"check-level": 2,
|
||||||
|
// turn off custom allocator & symbolic functions to make LSAN do its magic
|
||||||
|
"CMAKE_PRESET": "sanitize",
|
||||||
|
// exclude seriously slow/problematic tests (laketests crash)
|
||||||
|
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
|
||||||
|
},*/
|
||||||
|
{
|
||||||
|
"name": "macOS",
|
||||||
|
"os": "macos-13",
|
||||||
|
"release": true,
|
||||||
|
"check-level": 2,
|
||||||
|
"shell": "bash -euxo pipefail {0}",
|
||||||
|
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst",
|
||||||
|
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
||||||
|
"binary-check": "otool -L",
|
||||||
|
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "macOS aarch64",
|
||||||
|
"os": "macos-14",
|
||||||
|
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
|
||||||
|
"release": true,
|
||||||
|
"check-level": 0,
|
||||||
|
"shell": "bash -euxo pipefail {0}",
|
||||||
|
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-apple-darwin.tar.zst",
|
||||||
|
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
|
||||||
|
"binary-check": "otool -L",
|
||||||
|
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Windows",
|
||||||
|
"os": "windows-2022",
|
||||||
|
"release": true,
|
||||||
|
"check-level": 2,
|
||||||
|
"shell": "msys2 {0}",
|
||||||
|
"CMAKE_OPTIONS": "-G \"Unix Makefiles\" -DUSE_GMP=OFF",
|
||||||
|
// for reasons unknown, interactivetests are flaky on Windows
|
||||||
|
"CTEST_OPTIONS": "--repeat until-pass:2",
|
||||||
|
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
|
||||||
|
"prepare-llvm": "../script/prepare-llvm-mingw.sh lean-llvm*",
|
||||||
|
"binary-check": "ldd"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Linux aarch64",
|
||||||
|
"os": "nscloud-ubuntu-22.04-arm64-4x8",
|
||||||
|
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64",
|
||||||
|
"release": true,
|
||||||
|
"check-level": 2,
|
||||||
|
"shell": "nix develop .#oldGlibcAArch -c bash -euxo pipefail {0}",
|
||||||
|
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst",
|
||||||
|
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Linux 32bit",
|
||||||
|
"os": "ubuntu-latest",
|
||||||
|
// Use 32bit on stage0 and stage1 to keep oleans compatible
|
||||||
|
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86 -DCMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/ -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/",
|
||||||
|
"cmultilib": true,
|
||||||
|
"release": true,
|
||||||
|
"check-level": 2,
|
||||||
|
"cross": true,
|
||||||
|
"shell": "bash -euxo pipefail {0}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Web Assembly",
|
||||||
|
"os": "ubuntu-latest",
|
||||||
|
// Build a native 32bit binary in stage0 and use it to compile the oleans and the wasm build
|
||||||
|
"CMAKE_OPTIONS": "-DCMAKE_C_COMPILER_WORKS=1 -DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_CMAKE_CXX_COMPILER=clang++ -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_EXECUTABLE_SUFFIX=\"\" -DUSE_GMP=OFF -DMMAP=OFF -DSTAGE0_MMAP=OFF -DCMAKE_AR=../emsdk/emsdk-main/upstream/emscripten/emar -DCMAKE_TOOLCHAIN_FILE=../emsdk/emsdk-main/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DLEAN_INSTALL_SUFFIX=-linux_wasm32 -DSTAGE0_CMAKE_LIBRARY_PATH=/usr/lib/i386-linux-gnu/",
|
||||||
|
"wasm": true,
|
||||||
|
"cmultilib": true,
|
||||||
|
"release": true,
|
||||||
|
"check-level": 2,
|
||||||
|
"cross": true,
|
||||||
|
"shell": "bash -euxo pipefail {0}",
|
||||||
|
// Just a few selected tests because wasm is slow
|
||||||
|
"CTEST_OPTIONS": "-R \"leantest_1007\\.lean|leantest_Format\\.lean|leanruntest\\_1037.lean|leanruntest_ac_rfl\\.lean|leanruntest_libuv\\.lean\""
|
||||||
|
}
|
||||||
|
];
|
||||||
|
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`)
|
||||||
|
return matrix.filter((job) => level >= job["check-level"])
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: [configure]
|
needs: [configure]
|
||||||
if: github.event_name != 'schedule' || github.repository == 'leanprover/lean4'
|
if: github.event_name != 'schedule' || github.repository == 'leanprover/lean4'
|
||||||
@@ -275,28 +289,34 @@ jobs:
|
|||||||
CXX: c++
|
CXX: c++
|
||||||
MACOSX_DEPLOYMENT_TARGET: 10.15
|
MACOSX_DEPLOYMENT_TARGET: 10.15
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: cachix/install-nix-action@v18
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
with:
|
|
||||||
install_url: https://releases.nixos.org/nix/nix-2.12.0/install
|
|
||||||
if: runner.os == 'Linux' && !matrix.cmultilib
|
if: runner.os == 'Linux' && !matrix.cmultilib
|
||||||
- name: Install MSYS2
|
- name: Install MSYS2
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
with:
|
with:
|
||||||
msystem: clang64
|
msystem: clang64
|
||||||
# `:p` means prefix with appropriate msystem prefix
|
# `:` means do not prefix with msystem
|
||||||
pacboy: "make python cmake:p clang:p ccache:p gmp:p git zip unzip diffutils binutils tree zstd:p tar"
|
pacboy: "make: python: cmake clang ccache gmp libuv git: zip: unzip: diffutils: binutils: tree: zstd tar:"
|
||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
- name: Install Brew Packages
|
- name: Install Brew Packages
|
||||||
run: |
|
run: |
|
||||||
brew install ccache tree zstd coreutils gmp
|
brew install ccache tree zstd coreutils gmp libuv
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||||
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
|
# Do check out some CI-relevant files from virtual merge commit to accommodate CI changes on
|
||||||
|
# master (as the workflow files themselves are always taken from the merge)
|
||||||
|
# (needs to be after "Install *" to use the right shell)
|
||||||
|
- name: CI Merge Checkout
|
||||||
|
run: |
|
||||||
|
git fetch --depth=1 origin ${{ github.sha }}
|
||||||
|
git checkout FETCH_HEAD flake.nix flake.lock
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
# (needs to be after "Checkout" so files don't get overriden)
|
||||||
- name: Setup emsdk
|
- name: Setup emsdk
|
||||||
uses: mymindstorm/setup-emsdk@v12
|
uses: mymindstorm/setup-emsdk@v12
|
||||||
with:
|
with:
|
||||||
@@ -305,33 +325,31 @@ jobs:
|
|||||||
if: matrix.wasm
|
if: matrix.wasm
|
||||||
- name: Install 32bit c libs
|
- name: Install 32bit c libs
|
||||||
run: |
|
run: |
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install -y gcc-multilib g++-multilib ccache
|
sudo apt-get install -y gcc-multilib g++-multilib ccache libuv1-dev:i386
|
||||||
if: matrix.cmultilib
|
if: matrix.cmultilib
|
||||||
- name: Cache
|
- name: Cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: .ccache
|
path: .ccache
|
||||||
key: ${{ matrix.name }}-build-v3-${{ github.sha }}
|
key: ${{ matrix.name }}-build-v3-${{ github.event.pull_request.head.sha }}
|
||||||
# fall back to (latest) previous cache
|
# fall back to (latest) previous cache
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.name }}-build-v3
|
${{ matrix.name }}-build-v3
|
||||||
|
save-always: true
|
||||||
|
# open nix-shell once for initial setup
|
||||||
- name: Setup
|
- name: Setup
|
||||||
run: |
|
run: |
|
||||||
# open nix-shell once for initial setup
|
ccache --zero-stats
|
||||||
true
|
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
- name: Set up core dumps
|
- name: Set up NPROC
|
||||||
run: |
|
run: |
|
||||||
mkdir -p $PWD/coredumps
|
echo "NPROC=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)" >> $GITHUB_ENV
|
||||||
# store in current directory, for easy uploading together with binary
|
|
||||||
echo $PWD/coredumps/%e.%p.%t | sudo tee /proc/sys/kernel/core_pattern
|
|
||||||
if: runner.os == 'Linux'
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
ulimit -c unlimited # coredumps
|
|
||||||
# arguments passed to `cmake`
|
# arguments passed to `cmake`
|
||||||
# this also enables githash embedding into stage 1 library
|
# this also enables githash embedding into stage 1 library
|
||||||
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
|
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
|
||||||
@@ -357,11 +375,19 @@ jobs:
|
|||||||
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ needs.configure.outputs.LEAN_SPECIAL_VERSION_DESC }})
|
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ needs.configure.outputs.LEAN_SPECIAL_VERSION_DESC }})
|
||||||
fi
|
fi
|
||||||
# contortion to support empty OPTIONS with old macOS bash
|
# contortion to support empty OPTIONS with old macOS bash
|
||||||
cmake .. ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
|
cmake .. --preset ${{ matrix.CMAKE_PRESET || 'release' }} -B . ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
|
||||||
make -j4
|
time make -j$NPROC
|
||||||
make install
|
- name: Install
|
||||||
|
run: |
|
||||||
|
make -C build install
|
||||||
- name: Check Binaries
|
- name: Check Binaries
|
||||||
run: ${{ matrix.binary-check }} lean-*/bin/* || true
|
run: ${{ matrix.binary-check }} lean-*/bin/* || true
|
||||||
|
- name: Count binary symbols
|
||||||
|
run: |
|
||||||
|
for f in lean-*/bin/*; do
|
||||||
|
echo "$f: $(nm $f | grep " T " | wc -l) exported symbols"
|
||||||
|
done
|
||||||
|
if: matrix.name == 'Windows'
|
||||||
- name: List Install Tree
|
- name: List Install Tree
|
||||||
run: |
|
run: |
|
||||||
# omit contents of Init/, ...
|
# omit contents of Init/, ...
|
||||||
@@ -377,7 +403,7 @@ jobs:
|
|||||||
else
|
else
|
||||||
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -o pack/$dir.tar.zst
|
${{ matrix.tar || 'tar' }} cf - $dir | zstd -T0 --no-progress -o pack/$dir.tar.zst
|
||||||
fi
|
fi
|
||||||
- uses: actions/upload-artifact@v3
|
- uses: actions/upload-artifact@v4
|
||||||
if: matrix.release
|
if: matrix.release
|
||||||
with:
|
with:
|
||||||
name: build-${{ matrix.name }}
|
name: build-${{ matrix.name }}
|
||||||
@@ -387,71 +413,43 @@ jobs:
|
|||||||
build/stage1/bin/lean --stats src/Lean.lean
|
build/stage1/bin/lean --stats src/Lean.lean
|
||||||
if: ${{ !matrix.cross }}
|
if: ${{ !matrix.cross }}
|
||||||
- name: Test
|
- name: Test
|
||||||
|
id: test
|
||||||
run: |
|
run: |
|
||||||
cd build/stage1
|
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||||
ulimit -c unlimited # coredumps
|
if: (matrix.wasm || !matrix.cross) && needs.configure.outputs.check-level >= 1
|
||||||
# exclude nonreproducible test
|
|
||||||
ctest -j4 --progress --output-junit test-results.xml --output-on-failure ${{ matrix.CTEST_OPTIONS }} < /dev/null
|
|
||||||
if: (matrix.wasm || !matrix.cross) && needs.configure.outputs.quick == 'false'
|
|
||||||
- name: Test Summary
|
- name: Test Summary
|
||||||
uses: test-summary/action@v2
|
uses: test-summary/action@v2
|
||||||
with:
|
with:
|
||||||
paths: build/stage1/test-results.xml
|
paths: build/stage1/test-results.xml
|
||||||
# prefix `if` above with `always` so it's run even if tests failed
|
# prefix `if` above with `always` so it's run even if tests failed
|
||||||
if: always() && (matrix.wasm || !matrix.cross) && needs.configure.outputs.quick == 'false'
|
if: always() && steps.test.conclusion != 'skipped'
|
||||||
- name: Check Test Binary
|
- name: Check Test Binary
|
||||||
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
|
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
|
||||||
if: ${{ !matrix.cross && needs.configure.outputs.quick == 'false' }}
|
if: (!matrix.cross) && steps.test.conclusion != 'skipped'
|
||||||
- name: Build Stage 2
|
- name: Build Stage 2
|
||||||
run: |
|
run: |
|
||||||
cd build
|
make -C build -j$NPROC stage2
|
||||||
ulimit -c unlimited # coredumps
|
|
||||||
make -j4 stage2
|
|
||||||
if: matrix.test-speedcenter
|
if: matrix.test-speedcenter
|
||||||
- name: Check Stage 3
|
- name: Check Stage 3
|
||||||
run: |
|
run: |
|
||||||
cd build
|
make -C build -j$NPROC check-stage3
|
||||||
ulimit -c unlimited # coredumps
|
|
||||||
make -j4 check-stage3
|
|
||||||
if: matrix.test-speedcenter
|
if: matrix.test-speedcenter
|
||||||
- name: Test Speedcenter Benchmarks
|
- name: Test Speedcenter Benchmarks
|
||||||
run: |
|
run: |
|
||||||
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
|
# Necessary for some timing metrics but does not work on Namespace runners
|
||||||
|
# and we just want to test that the benchmarks run at all here
|
||||||
|
#echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
|
||||||
export BUILD=$PWD/build PATH=$PWD/build/stage1/bin:$PATH
|
export BUILD=$PWD/build PATH=$PWD/build/stage1/bin:$PATH
|
||||||
cd tests/bench
|
cd tests/bench
|
||||||
nix shell .#temci -c temci exec --config speedcenter.yaml --included_blocks fast --runs 1
|
nix shell .#temci -c temci exec --config speedcenter.yaml --included_blocks fast --runs 1
|
||||||
if: matrix.test-speedcenter
|
if: matrix.test-speedcenter
|
||||||
- name: Check rebootstrap
|
- name: Check rebootstrap
|
||||||
run: |
|
run: |
|
||||||
cd build
|
|
||||||
ulimit -c unlimited # coredumps
|
|
||||||
# clean rebuild in case of Makefile changes
|
# clean rebuild in case of Makefile changes
|
||||||
make update-stage0 && rm -rf ./stage* && make -j4
|
make -C build update-stage0 && rm -rf build/stage* && make -C build -j$NPROC
|
||||||
if: matrix.name == 'Linux' && needs.configure.outputs.quick == 'false'
|
if: matrix.name == 'Linux' && needs.configure.outputs.check-level >= 1
|
||||||
- name: CCache stats
|
- name: CCache stats
|
||||||
run: ccache -s
|
run: ccache -s
|
||||||
- name: Show stacktrace for coredumps
|
|
||||||
if: ${{ failure() && runner.os == 'Linux' }}
|
|
||||||
run: |
|
|
||||||
for c in coredumps/*; do
|
|
||||||
progbin="$(file $c | sed "s/.*execfn: '\([^']*\)'.*/\1/")"
|
|
||||||
echo bt | $GDB/bin/gdb -q $progbin $c || true
|
|
||||||
done
|
|
||||||
# has not been used in a long while, would need to be adapted to new
|
|
||||||
# shared libs
|
|
||||||
#- name: Upload coredumps
|
|
||||||
# uses: actions/upload-artifact@v3
|
|
||||||
# if: ${{ failure() && runner.os == 'Linux' }}
|
|
||||||
# with:
|
|
||||||
# name: coredumps-${{ matrix.name }}
|
|
||||||
# path: |
|
|
||||||
# ./coredumps
|
|
||||||
# ./build/stage0/bin/lean
|
|
||||||
# ./build/stage0/lib/lean/libleanshared.so
|
|
||||||
# ./build/stage1/bin/lean
|
|
||||||
# ./build/stage1/lib/lean/libleanshared.so
|
|
||||||
# ./build/stage2/bin/lean
|
|
||||||
# ./build/stage2/lib/lean/libleanshared.so
|
|
||||||
|
|
||||||
# This job collects results from all the matrix jobs
|
# This job collects results from all the matrix jobs
|
||||||
# This can be made the “required” job, instead of listing each
|
# This can be made the “required” job, instead of listing each
|
||||||
@@ -463,12 +461,24 @@ jobs:
|
|||||||
# mark as merely cancelled not failed if builds are cancelled
|
# mark as merely cancelled not failed if builds are cancelled
|
||||||
if: ${{ !cancelled() }}
|
if: ${{ !cancelled() }}
|
||||||
steps:
|
steps:
|
||||||
|
- if: ${{ contains(needs.*.result, 'failure') && github.repository == 'leanprover/lean4' && github.ref_name == 'master' }}
|
||||||
|
uses: zulip/github-actions-zulip/send-message@v1
|
||||||
|
with:
|
||||||
|
api-key: ${{ secrets.ZULIP_BOT_KEY }}
|
||||||
|
email: "github-actions-bot@lean-fro.zulipchat.com"
|
||||||
|
organization-url: "https://lean-fro.zulipchat.com"
|
||||||
|
to: "infrastructure"
|
||||||
|
topic: "Github actions"
|
||||||
|
type: "stream"
|
||||||
|
content: |
|
||||||
|
A build of `${{ github.ref_name }}`, triggered by event `${{ github.event_name }}`, [failed](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}).
|
||||||
- if: contains(needs.*.result, 'failure')
|
- if: contains(needs.*.result, 'failure')
|
||||||
uses: actions/github-script@v7
|
uses: actions/github-script@v7
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
core.setFailed('Some jobs failed')
|
core.setFailed('Some jobs failed')
|
||||||
|
|
||||||
|
|
||||||
# This job creates releases from tags
|
# This job creates releases from tags
|
||||||
# (whether they are "unofficial" releases for experiments, or official releases when the tag is "v" followed by a semver string.)
|
# (whether they are "unofficial" releases for experiments, or official releases when the tag is "v" followed by a semver string.)
|
||||||
# We do not attempt to automatically construct a changelog here:
|
# We do not attempt to automatically construct a changelog here:
|
||||||
@@ -478,7 +488,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: build
|
needs: build
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
- name: Release
|
- name: Release
|
||||||
@@ -486,8 +496,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
files: artifacts/*/*
|
files: artifacts/*/*
|
||||||
fail_on_unmatched_files: true
|
fail_on_unmatched_files: true
|
||||||
|
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-rc') }}
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Update release.lean-lang.org
|
||||||
|
run: |
|
||||||
|
gh workflow -R leanprover/release-index run update-index.yml
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.RELEASE_INDEX_TOKEN }}
|
||||||
|
|
||||||
# This job creates nightly releases during the cron job.
|
# This job creates nightly releases during the cron job.
|
||||||
# It is responsible for creating the tag, and automatically generating a changelog.
|
# It is responsible for creating the tag, and automatically generating a changelog.
|
||||||
@@ -497,12 +513,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
# needed for tagging
|
# needed for tagging
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
token: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
- name: Prepare Nightly Release
|
- name: Prepare Nightly Release
|
||||||
@@ -530,3 +546,13 @@ jobs:
|
|||||||
repository: ${{ github.repository_owner }}/lean4-nightly
|
repository: ${{ github.repository_owner }}/lean4-nightly
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.PUSH_NIGHTLY_TOKEN }}
|
||||||
|
- name: Update release.lean-lang.org
|
||||||
|
run: |
|
||||||
|
gh workflow -R leanprover/release-index run update-index.yml
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.RELEASE_INDEX_TOKEN }}
|
||||||
|
- name: Update toolchain on mathlib4's nightly-testing branch
|
||||||
|
run: |
|
||||||
|
gh workflow -R leanprover-community/mathlib4 run nightly_bump_toolchain.yml
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.MATHLIB4_BOT }}
|
||||||
|
|||||||
34
.github/workflows/jira.yml
vendored
Normal file
34
.github/workflows/jira.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Jira sync
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [closed]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
jira-sync:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Move Jira issue to Done
|
||||||
|
env:
|
||||||
|
JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }}
|
||||||
|
JIRA_USERNAME: ${{ secrets.JIRA_USERNAME }}
|
||||||
|
JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }}
|
||||||
|
run: |
|
||||||
|
issue_number=${{ github.event.issue.number }}
|
||||||
|
|
||||||
|
jira_issue_key=$(curl -s -u "${JIRA_USERNAME}:${JIRA_API_TOKEN}" \
|
||||||
|
-X GET -H "Content-Type: application/json" \
|
||||||
|
"${JIRA_BASE_URL}/rest/api/2/search?jql=summary~\"${issue_number}\"" | \
|
||||||
|
jq -r '.issues[0].key')
|
||||||
|
|
||||||
|
if [ -z "$jira_issue_key" ]; then
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -s -u "${JIRA_USERNAME}:${JIRA_API_TOKEN}" \
|
||||||
|
-X POST -H "Content-Type: application/json" \
|
||||||
|
--data "{\"transition\": {\"id\": \"41\"}}" \
|
||||||
|
"${JIRA_BASE_URL}/rest/api/2/issue/${jira_issue_key}/transitions"
|
||||||
|
|
||||||
|
echo "Moved Jira issue ${jira_issue_key} to Done"
|
||||||
40
.github/workflows/nix-ci.yml
vendored
40
.github/workflows/nix-ci.yml
vendored
@@ -13,18 +13,36 @@ concurrency:
|
|||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# see ci.yml
|
||||||
|
configure:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
matrix: ${{ steps.set-matrix.outputs.result }}
|
||||||
|
steps:
|
||||||
|
- name: Configure build matrix
|
||||||
|
id: set-matrix
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
let large = ${{ github.repository == 'leanprover/lean4' }};
|
||||||
|
let matrix = [
|
||||||
|
{
|
||||||
|
"name": "Nix Linux",
|
||||||
|
"os": large ? "nscloud-ubuntu-22.04-amd64-8x8" : "ubuntu-latest",
|
||||||
|
}
|
||||||
|
];
|
||||||
|
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`);
|
||||||
|
return matrix;
|
||||||
|
|
||||||
Build:
|
Build:
|
||||||
|
needs: [configure]
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
shell: nix run .#ciShell -- bash -euxo pipefail {0}
|
shell: nix run .#ciShell -- bash -euxo pipefail {0}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include: ${{fromJson(needs.configure.outputs.matrix)}}
|
||||||
- name: Nix Linux
|
|
||||||
os: ubuntu-latest
|
|
||||||
#- name: Nix macOS
|
|
||||||
# os: macos-latest
|
|
||||||
# complete all jobs
|
# complete all jobs
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
name: ${{ matrix.name }}
|
name: ${{ matrix.name }}
|
||||||
@@ -32,18 +50,19 @@ jobs:
|
|||||||
NIX_BUILD_ARGS: --print-build-logs --fallback
|
NIX_BUILD_ARGS: --print-build-logs --fallback
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||||
ref: ${{ github.event.pull_request.head.sha }}
|
ref: ${{ github.event.pull_request.head.sha }}
|
||||||
- name: Set Up Nix Cache
|
- name: Set Up Nix Cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: nix-store-cache
|
path: nix-store-cache
|
||||||
key: ${{ matrix.name }}-nix-store-cache-${{ github.sha }}
|
key: ${{ matrix.name }}-nix-store-cache-${{ github.sha }}
|
||||||
# fall back to (latest) previous cache
|
# fall back to (latest) previous cache
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.name }}-nix-store-cache
|
${{ matrix.name }}-nix-store-cache
|
||||||
|
save-always: true
|
||||||
- name: Further Set Up Nix Cache
|
- name: Further Set Up Nix Cache
|
||||||
shell: bash -euxo pipefail {0}
|
shell: bash -euxo pipefail {0}
|
||||||
run: |
|
run: |
|
||||||
@@ -60,13 +79,14 @@ jobs:
|
|||||||
sudo mkdir -m0770 -p /nix/var/cache/ccache
|
sudo mkdir -m0770 -p /nix/var/cache/ccache
|
||||||
sudo chown -R $USER /nix/var/cache/ccache
|
sudo chown -R $USER /nix/var/cache/ccache
|
||||||
- name: Setup CCache Cache
|
- name: Setup CCache Cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: /nix/var/cache/ccache
|
path: /nix/var/cache/ccache
|
||||||
key: ${{ matrix.name }}-nix-ccache-${{ github.sha }}
|
key: ${{ matrix.name }}-nix-ccache-${{ github.sha }}
|
||||||
# fall back to (latest) previous cache
|
# fall back to (latest) previous cache
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.name }}-nix-ccache
|
${{ matrix.name }}-nix-ccache
|
||||||
|
save-always: true
|
||||||
- name: Further Set Up CCache Cache
|
- name: Further Set Up CCache Cache
|
||||||
run: |
|
run: |
|
||||||
sudo chown -R root:nixbld /nix/var/cache
|
sudo chown -R root:nixbld /nix/var/cache
|
||||||
@@ -85,7 +105,7 @@ jobs:
|
|||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
- name: Build manual
|
- name: Build manual
|
||||||
run: |
|
run: |
|
||||||
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc#{lean-mdbook,leanInk,alectryon,test,inked} -o push-doc
|
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc#{lean-mdbook,leanInk,alectryon,inked} -o push-doc
|
||||||
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc
|
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc
|
||||||
# https://github.com/netlify/cli/issues/1809
|
# https://github.com/netlify/cli/issues/1809
|
||||||
cp -r --dereference ./result ./dist
|
cp -r --dereference ./result ./dist
|
||||||
@@ -128,5 +148,3 @@ jobs:
|
|||||||
- name: Fixup CCache Cache
|
- name: Fixup CCache Cache
|
||||||
run: |
|
run: |
|
||||||
sudo chown -R $USER /nix/var/cache
|
sudo chown -R $USER /nix/var/cache
|
||||||
- name: CCache stats
|
|
||||||
run: CCACHE_DIR=/nix/var/cache/ccache nix run .#nixpkgs.ccache -- -s
|
|
||||||
|
|||||||
19
.github/workflows/pr-release.yml
vendored
19
.github/workflows/pr-release.yml
vendored
@@ -163,7 +163,8 @@ jobs:
|
|||||||
# so keep in sync
|
# so keep in sync
|
||||||
|
|
||||||
# Use GitHub API to check if a comment already exists
|
# Use GitHub API to check if a comment already exists
|
||||||
existing_comment="$(curl -L -s -H "Authorization: token ${{ secrets.MATHLIB4_BOT }}" \
|
existing_comment="$(curl --retry 3 --location --silent \
|
||||||
|
-H "Authorization: token ${{ secrets.MATHLIB4_BOT }}" \
|
||||||
-H "Accept: application/vnd.github.v3+json" \
|
-H "Accept: application/vnd.github.v3+json" \
|
||||||
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments" \
|
"https://api.github.com/repos/leanprover/lean4/issues/${{ steps.workflow-info.outputs.pullRequestNumber }}/comments" \
|
||||||
| jq 'first(.[] | select(.body | test("^- . Mathlib") or startswith("Mathlib CI status")) | select(.user.login == "leanprover-community-mathlib4-bot"))')"
|
| jq 'first(.[] | select(.body | test("^- . Mathlib") or startswith("Mathlib CI status")) | select(.user.login == "leanprover-community-mathlib4-bot"))')"
|
||||||
@@ -234,7 +235,7 @@ jobs:
|
|||||||
# Checkout the Batteries repository with all branches
|
# Checkout the Batteries repository with all branches
|
||||||
- name: Checkout Batteries repository
|
- name: Checkout Batteries repository
|
||||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: leanprover-community/batteries
|
repository: leanprover-community/batteries
|
||||||
token: ${{ secrets.MATHLIB4_BOT }}
|
token: ${{ secrets.MATHLIB4_BOT }}
|
||||||
@@ -291,13 +292,20 @@ jobs:
|
|||||||
# Checkout the mathlib4 repository with all branches
|
# Checkout the mathlib4 repository with all branches
|
||||||
- name: Checkout mathlib4 repository
|
- name: Checkout mathlib4 repository
|
||||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
repository: leanprover-community/mathlib4
|
repository: leanprover-community/mathlib4
|
||||||
token: ${{ secrets.MATHLIB4_BOT }}
|
token: ${{ secrets.MATHLIB4_BOT }}
|
||||||
ref: nightly-testing
|
ref: nightly-testing
|
||||||
fetch-depth: 0 # This ensures we check out all tags and branches.
|
fetch-depth: 0 # This ensures we check out all tags and branches.
|
||||||
|
|
||||||
|
- name: install elan
|
||||||
|
run: |
|
||||||
|
set -o pipefail
|
||||||
|
curl -sSfL https://github.com/leanprover/elan/releases/download/v3.0.0/elan-x86_64-unknown-linux-gnu.tar.gz | tar xz
|
||||||
|
./elan-init -y --default-toolchain none
|
||||||
|
echo "$HOME/.elan/bin" >> "${GITHUB_PATH}"
|
||||||
|
|
||||||
- name: Check if tag exists
|
- name: Check if tag exists
|
||||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||||
id: check_mathlib_tag
|
id: check_mathlib_tag
|
||||||
@@ -321,8 +329,9 @@ jobs:
|
|||||||
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
|
||||||
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
|
||||||
git add lean-toolchain
|
git add lean-toolchain
|
||||||
sed -i "s/require batteries from git \"https:\/\/github.com\/leanprover-community\/batteries\" @ \".\+\"/require batteries from git \"https:\/\/github.com\/leanprover-community\/batteries\" @ \"nightly-testing-${MOST_RECENT_NIGHTLY}\"/" lakefile.lean
|
sed -i 's,require "leanprover-community" / "batteries" @ git ".\+",require "leanprover-community" / "batteries" @ git "nightly-testing-'"${MOST_RECENT_NIGHTLY}"'",' lakefile.lean
|
||||||
git add lakefile.lean
|
lake update batteries
|
||||||
|
git add lakefile.lean lake-manifest.json
|
||||||
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
|
||||||
else
|
else
|
||||||
echo "Branch already exists, pushing an empty commit."
|
echo "Branch already exists, pushing an empty commit."
|
||||||
|
|||||||
14
.github/workflows/restart-on-label.yml
vendored
14
.github/workflows/restart-on-label.yml
vendored
@@ -7,25 +7,29 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
restart-on-label:
|
restart-on-label:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: contains(github.event.label.name, 'full-ci')
|
if: contains(github.event.label.name, 'merge-ci') || contains(github.event.label.name, 'release-ci')
|
||||||
steps:
|
steps:
|
||||||
- run: |
|
- run: |
|
||||||
# Finding latest CI workflow run on current pull request
|
# Finding latest CI workflow run on current pull request
|
||||||
# (unfortunately cannot search by PR number, only base branch,
|
# (unfortunately cannot search by PR number, only base branch,
|
||||||
# and that is't even unique given PRs from forks, but the risk
|
# and that is't even unique given PRs from forks, but the risk
|
||||||
# of confusion is low and the danger is mild)
|
# of confusion is low and the danger is mild)
|
||||||
run_id=$(gh run list -e pull_request -b "$head_ref" --workflow 'CI' --limit 1 \
|
echo "Trying to find a run with branch $head_ref and commit $head_sha"
|
||||||
--limit 1 --json databaseId --jq '.[0].databaseId')
|
run_id="$(gh run list -e pull_request -b "$head_ref" -c "$head_sha" \
|
||||||
|
--workflow 'CI' --limit 1 --json databaseId --jq '.[0].databaseId')"
|
||||||
echo "Run id: ${run_id}"
|
echo "Run id: ${run_id}"
|
||||||
gh run view "$run_id"
|
gh run view "$run_id"
|
||||||
echo "Cancelling (just in case)"
|
echo "Cancelling (just in case)"
|
||||||
gh run cancel "$run_id" || echo "(failed)"
|
gh run cancel "$run_id" || echo "(failed)"
|
||||||
echo "Waiting for 10s"
|
echo "Waiting for 30s"
|
||||||
sleep 10
|
sleep 30
|
||||||
|
gh run view "$run_id"
|
||||||
echo "Rerunning"
|
echo "Rerunning"
|
||||||
gh run rerun "$run_id"
|
gh run rerun "$run_id"
|
||||||
|
gh run view "$run_id"
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
head_ref: ${{ github.head_ref }}
|
head_ref: ${{ github.head_ref }}
|
||||||
|
head_sha: ${{ github.event.pull_request.head.sha }}
|
||||||
GH_TOKEN: ${{ github.token }}
|
GH_TOKEN: ${{ github.token }}
|
||||||
GH_REPO: ${{ github.repository }}
|
GH_REPO: ${{ github.repository }}
|
||||||
|
|||||||
4
.github/workflows/update-stage0.yml
vendored
4
.github/workflows/update-stage0.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
# This action should push to an otherwise protected branch, so it
|
# This action should push to an otherwise protected branch, so it
|
||||||
# uses a deploy key with write permissions, as suggested at
|
# uses a deploy key with write permissions, as suggested at
|
||||||
# https://stackoverflow.com/a/76135647/946226
|
# https://stackoverflow.com/a/76135647/946226
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
|
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
|
||||||
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
|
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
# uses: DeterminateSystems/magic-nix-cache-action@v2
|
# uses: DeterminateSystems/magic-nix-cache-action@v2
|
||||||
- if: env.should_update_stage0 == 'yes'
|
- if: env.should_update_stage0 == 'yes'
|
||||||
name: Restore Build Cache
|
name: Restore Build Cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
with:
|
with:
|
||||||
path: nix-store-cache
|
path: nix-store-cache
|
||||||
key: Nix Linux-nix-store-cache-${{ github.sha }}
|
key: Nix Linux-nix-store-cache-${{ github.sha }}
|
||||||
|
|||||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -4,8 +4,10 @@
|
|||||||
*.lock
|
*.lock
|
||||||
.lake
|
.lake
|
||||||
lake-manifest.json
|
lake-manifest.json
|
||||||
build
|
/build
|
||||||
!/src/lake/Lake/Build
|
/src/lakefile.toml
|
||||||
|
/tests/lakefile.toml
|
||||||
|
/lakefile.toml
|
||||||
GPATH
|
GPATH
|
||||||
GRTAGS
|
GRTAGS
|
||||||
GSYMS
|
GSYMS
|
||||||
|
|||||||
@@ -30,6 +30,35 @@ if(NOT (DEFINED STAGE0_CMAKE_EXECUTABLE_SUFFIX))
|
|||||||
set(STAGE0_CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}")
|
set(STAGE0_CMAKE_EXECUTABLE_SUFFIX "${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Don't do anything with cadical on wasm
|
||||||
|
if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
|
# On CI Linux, we source cadical from Nix instead; see flake.nix
|
||||||
|
find_program(CADICAL cadical)
|
||||||
|
if(NOT CADICAL)
|
||||||
|
set(CADICAL_CXX c++)
|
||||||
|
find_program(CCACHE ccache)
|
||||||
|
if(CCACHE)
|
||||||
|
set(CADICAL_CXX "${CCACHE} ${CADICAL_CXX}")
|
||||||
|
endif()
|
||||||
|
# missing stdio locking API on Windows
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||||
|
string(APPEND CADICAL_CXXFLAGS " -DNUNLOCKED")
|
||||||
|
endif()
|
||||||
|
ExternalProject_add(cadical
|
||||||
|
PREFIX cadical
|
||||||
|
GIT_REPOSITORY https://github.com/arminbiere/cadical
|
||||||
|
GIT_TAG rel-1.9.5
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
# https://github.com/arminbiere/cadical/blob/master/BUILD.md#manual-build
|
||||||
|
BUILD_COMMAND $(MAKE) -f ${CMAKE_SOURCE_DIR}/src/cadical.mk CMAKE_EXECUTABLE_SUFFIX=${CMAKE_EXECUTABLE_SUFFIX} CXX=${CADICAL_CXX} CXXFLAGS=${CADICAL_CXXFLAGS}
|
||||||
|
BUILD_IN_SOURCE ON
|
||||||
|
INSTALL_COMMAND "")
|
||||||
|
set(CADICAL ${CMAKE_BINARY_DIR}/cadical/cadical${CMAKE_EXECUTABLE_SUFFIX} CACHE FILEPATH "path to cadical binary" FORCE)
|
||||||
|
set(EXTRA_DEPENDS "cadical")
|
||||||
|
endif()
|
||||||
|
list(APPEND CL_ARGS -DCADICAL=${CADICAL})
|
||||||
|
endif()
|
||||||
|
|
||||||
ExternalProject_add(stage0
|
ExternalProject_add(stage0
|
||||||
SOURCE_DIR "${LEAN_SOURCE_DIR}/stage0"
|
SOURCE_DIR "${LEAN_SOURCE_DIR}/stage0"
|
||||||
SOURCE_SUBDIR src
|
SOURCE_SUBDIR src
|
||||||
|
|||||||
83
CMakePresets.json
Normal file
83
CMakePresets.json
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"cmakeMinimumRequired": {
|
||||||
|
"major": 3,
|
||||||
|
"minor": 10,
|
||||||
|
"patch": 0
|
||||||
|
},
|
||||||
|
"configurePresets": [
|
||||||
|
{
|
||||||
|
"name": "release",
|
||||||
|
"displayName": "Default development optimized build config",
|
||||||
|
"generator": "Unix Makefiles",
|
||||||
|
"binaryDir": "${sourceDir}/build/release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"displayName": "Debug build config",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug"
|
||||||
|
},
|
||||||
|
"generator": "Unix Makefiles",
|
||||||
|
"binaryDir": "${sourceDir}/build/debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sanitize",
|
||||||
|
"displayName": "Sanitize build config",
|
||||||
|
"cacheVariables": {
|
||||||
|
"LEAN_EXTRA_CXX_FLAGS": "-fsanitize=address,undefined",
|
||||||
|
"LEANC_EXTRA_FLAGS": "-fsanitize=address,undefined -fsanitize-link-c++-runtime",
|
||||||
|
"SMALL_ALLOCATOR": "OFF",
|
||||||
|
"BSYMBOLIC": "OFF"
|
||||||
|
},
|
||||||
|
"generator": "Unix Makefiles",
|
||||||
|
"binaryDir": "${sourceDir}/build/sanitize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sandebug",
|
||||||
|
"inherits": ["debug", "sanitize"],
|
||||||
|
"displayName": "Sanitize+debug build config",
|
||||||
|
"binaryDir": "${sourceDir}/build/sandebug"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buildPresets": [
|
||||||
|
{
|
||||||
|
"name": "release",
|
||||||
|
"configurePreset": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"configurePreset": "debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sanitize",
|
||||||
|
"configurePreset": "sanitize"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sandebug",
|
||||||
|
"configurePreset": "sandebug"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"testPresets": [
|
||||||
|
{
|
||||||
|
"name": "release",
|
||||||
|
"configurePreset": "release",
|
||||||
|
"output": {"outputOnFailure": true, "shortProgress": true}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug",
|
||||||
|
"configurePreset": "debug",
|
||||||
|
"inherits": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sanitize",
|
||||||
|
"configurePreset": "sanitize",
|
||||||
|
"inherits": "release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "sandebug",
|
||||||
|
"configurePreset": "sandebug",
|
||||||
|
"inherits": "release"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -42,4 +42,6 @@
|
|||||||
/src/Lean/Elab/Tactic/Guard.lean @digama0
|
/src/Lean/Elab/Tactic/Guard.lean @digama0
|
||||||
/src/Init/Guard.lean @digama0
|
/src/Init/Guard.lean @digama0
|
||||||
/src/Lean/Server/CodeActions/ @digama0
|
/src/Lean/Server/CodeActions/ @digama0
|
||||||
|
/src/Std/ @TwoFX
|
||||||
|
/src/Std/Tactic/BVDecide/ @hargoniX
|
||||||
|
/src/Lean/Elab/Tactic/BVDecide/ @hargoniX
|
||||||
|
|||||||
@@ -63,6 +63,20 @@ Because the change will be squashed, there is no need to polish the commit messa
|
|||||||
Reviews and Feedback:
|
Reviews and Feedback:
|
||||||
----
|
----
|
||||||
|
|
||||||
|
The lean4 repo is managed by the Lean FRO's *triage team* that aims to provide initial feedback on new bug reports, PRs, and RFCs weekly.
|
||||||
|
This feedback generally consists of prioritizing the ticket using one of the following categories:
|
||||||
|
* label `P-high`: We will work on this issue
|
||||||
|
* label `P-medium`: We may work on this issue if we find the time
|
||||||
|
* label `P-low`: We are not planning to work on this issue
|
||||||
|
* *closed*: This issue is already fixed, it is not an issue, or is not sufficiently compatible with our roadmap for the project and we will not work on it nor accept external contributions on it
|
||||||
|
|
||||||
|
For *bug reports*, the listed priority reflects our commitment to fixing the issue.
|
||||||
|
It is generally indicative but not necessarily identical to the priority an external contribution addressing this bug would receive.
|
||||||
|
For *PRs* and *RFCs*, the priority reflects our commitment to reviewing them and getting them to an acceptable state.
|
||||||
|
Accepted RFCs are marked with the label `RFC accepted` and afterwards assigned a new "implementation" priority as with bug reports.
|
||||||
|
|
||||||
|
General guidelines for interacting with reviews and feedback:
|
||||||
|
|
||||||
**Be Patient**: Given the limited number of full-time maintainers and the volume of PRs, reviews may take some time.
|
**Be Patient**: Given the limited number of full-time maintainers and the volume of PRs, reviews may take some time.
|
||||||
|
|
||||||
**Engage Constructively**: Always approach feedback positively and constructively. Remember, reviews are about ensuring the best quality for the project, not personal criticism.
|
**Engage Constructively**: Always approach feedback positively and constructively. Remember, reviews are about ensuring the best quality for the project, not personal criticism.
|
||||||
|
|||||||
30
LICENSES
30
LICENSES
@@ -1341,3 +1341,33 @@ whether future versions of the GNU Lesser General Public License shall
|
|||||||
apply, that proxy's public statement of acceptance of any version is
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
permanent authorization for you to choose that version for the
|
permanent authorization for you to choose that version for the
|
||||||
Library.
|
Library.
|
||||||
|
==============================================================================
|
||||||
|
CaDiCaL is under the MIT License:
|
||||||
|
==============================================================================
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016-2021 Armin Biere, Johannes Kepler University Linz, Austria
|
||||||
|
Copyright (c) 2020-2021 Mathias Fleury, Johannes Kepler University Linz, Austria
|
||||||
|
Copyright (c) 2020-2021 Nils Froleyks, Johannes Kepler University Linz, Austria
|
||||||
|
Copyright (c) 2022-2024 Katalin Fazekas, Vienna University of Technology, Austria
|
||||||
|
Copyright (c) 2021-2024 Armin Biere, University of Freiburg, Germany
|
||||||
|
Copyright (c) 2021-2024 Mathias Fleury, University of Freiburg, Germany
|
||||||
|
Copyright (c) 2023-2024 Florian Pollitt, University of Freiburg, Germany
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
1069
RELEASES.md
1069
RELEASES.md
File diff suppressed because it is too large
Load Diff
10
doc/char.md
10
doc/char.md
@@ -1 +1,11 @@
|
|||||||
# Characters
|
# Characters
|
||||||
|
|
||||||
|
A value of type `Char`, also known as a character, is a [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value). It is represented using an unsigned 32-bit integer and is statically guaranteed to be a valid Unicode scalar value.
|
||||||
|
|
||||||
|
Syntactically, character literals are enclosed in single quotes.
|
||||||
|
```lean
|
||||||
|
#eval 'a' -- 'a'
|
||||||
|
#eval '∀' -- '∀'
|
||||||
|
```
|
||||||
|
|
||||||
|
Characters are ordered and can be decidably compared using the relational operators `=`, `<`, `≤`, `>`, `≥`.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Some notes on how to debug Lean, which may also be applicable to debugging Lean
|
|||||||
|
|
||||||
## Tracing
|
## Tracing
|
||||||
|
|
||||||
In `CoreM` and derived monads, we use `trace![traceCls] "msg with {interpolations}"` to fill the structured trace viewable with `set_option trace.traceCls true`.
|
In `CoreM` and derived monads, we use `trace[traceCls] "msg with {interpolations}"` to fill the structured trace viewable with `set_option trace.traceCls true`.
|
||||||
New trace classes have to be registered using `registerTraceClass` first.
|
New trace classes have to be registered using `registerTraceClass` first.
|
||||||
|
|
||||||
Notable trace classes:
|
Notable trace classes:
|
||||||
@@ -22,7 +22,9 @@ Notable trace classes:
|
|||||||
|
|
||||||
In pure contexts or when execution is aborted before the messages are finally printed, one can instead use the term `dbg_trace "msg with {interpolations}"; val` (`;` can also be replaced by a newline), which will print the message to stderr before evaluating `val`. `dbgTraceVal val` can be used as a shorthand for `dbg_trace "{val}"; val`.
|
In pure contexts or when execution is aborted before the messages are finally printed, one can instead use the term `dbg_trace "msg with {interpolations}"; val` (`;` can also be replaced by a newline), which will print the message to stderr before evaluating `val`. `dbgTraceVal val` can be used as a shorthand for `dbg_trace "{val}"; val`.
|
||||||
Note that if the return value is not actually used, the trace code is silently dropped as well.
|
Note that if the return value is not actually used, the trace code is silently dropped as well.
|
||||||
In the language server, stderr output is buffered and shown as messages after a command has been elaborated, unless the option `server.stderrAsMessages` is deactivated.
|
|
||||||
|
By default, such stderr output is buffered and shown as messages after a command has been elaborated, which is necessary to ensure deterministic ordering of messages under parallelism.
|
||||||
|
If Lean aborts the process before it can finish the command or takes too long to do that, using `-DstderrAsMessages=false` avoids this buffering and shows `dbg_trace` output (but not `trace`s or other diagnostics) immediately.
|
||||||
|
|
||||||
## Debuggers
|
## Debuggers
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ See below for the checklist for release candidates.
|
|||||||
|
|
||||||
We'll use `v4.6.0` as the intended release version as a running example.
|
We'll use `v4.6.0` as the intended release version as a running example.
|
||||||
|
|
||||||
- One week before the planned release, ensure that someone has written the first draft of the release blog post
|
- One week before the planned release, ensure that
|
||||||
|
(1) someone has written the release notes and
|
||||||
|
(2) someone has written the first draft of the release blog post.
|
||||||
|
If there is any material in `./releases_drafts/` on the `releases/v4.6.0` branch, then the release notes are not done.
|
||||||
|
(See the section "Writing the release notes".)
|
||||||
- `git checkout releases/v4.6.0`
|
- `git checkout releases/v4.6.0`
|
||||||
(This branch should already exist, from the release candidates.)
|
(This branch should already exist, from the release candidates.)
|
||||||
- `git pull`
|
- `git pull`
|
||||||
@@ -13,13 +17,6 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
|||||||
- `set(LEAN_VERSION_MINOR 6)` (for whichever `6` is appropriate)
|
- `set(LEAN_VERSION_MINOR 6)` (for whichever `6` is appropriate)
|
||||||
- `set(LEAN_VERSION_IS_RELEASE 1)`
|
- `set(LEAN_VERSION_IS_RELEASE 1)`
|
||||||
- (both of these should already be in place from the release candidates)
|
- (both of these should already be in place from the release candidates)
|
||||||
- It is possible that the `v4.6.0` section of `RELEASES.md` is out of sync between
|
|
||||||
`releases/v4.6.0` and `master`. This should be reconciled:
|
|
||||||
- Run `git diff master RELEASES.md`.
|
|
||||||
- You should expect to see additons on `master` in the `v4.7.0-rc1` section; ignore these.
|
|
||||||
(i.e. the new release notes for the upcoming release candidate).
|
|
||||||
- Reconcile discrepancies in the `v4.6.0` section,
|
|
||||||
usually via copy and paste and a commit to `releases/v4.6.0`.
|
|
||||||
- `git tag v4.6.0`
|
- `git tag v4.6.0`
|
||||||
- `git push $REMOTE v4.6.0`, where `$REMOTE` is the upstream Lean repository (e.g., `origin`, `upstream`)
|
- `git push $REMOTE v4.6.0`, where `$REMOTE` is the upstream Lean repository (e.g., `origin`, `upstream`)
|
||||||
- Now wait, while CI runs.
|
- Now wait, while CI runs.
|
||||||
@@ -30,8 +27,9 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
|||||||
you may want to start on the release candidate checklist now.
|
you may want to start on the release candidate checklist now.
|
||||||
- Go to https://github.com/leanprover/lean4/releases and verify that the `v4.6.0` release appears.
|
- Go to https://github.com/leanprover/lean4/releases and verify that the `v4.6.0` release appears.
|
||||||
- Edit the release notes on Github to select the "Set as the latest release".
|
- Edit the release notes on Github to select the "Set as the latest release".
|
||||||
- Copy and paste the Github release notes from the previous releases candidate for this version
|
- Follow the instructions in creating a release candidate for the "GitHub release notes" step,
|
||||||
(e.g. `v4.6.0-rc1`), and quickly sanity check.
|
now that we have a written `RELEASES.md` section.
|
||||||
|
Do a quick sanity check.
|
||||||
- Next, we will move a curated list of downstream repos to the latest stable release.
|
- Next, we will move a curated list of downstream repos to the latest stable release.
|
||||||
- For each of the repositories listed below:
|
- For each of the repositories listed below:
|
||||||
- Make a PR to `master`/`main` changing the toolchain to `v4.6.0`
|
- Make a PR to `master`/`main` changing the toolchain to `v4.6.0`
|
||||||
@@ -46,7 +44,6 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
|||||||
- We do this for the repositories:
|
- We do this for the repositories:
|
||||||
- [lean4checker](https://github.com/leanprover/lean4checker)
|
- [lean4checker](https://github.com/leanprover/lean4checker)
|
||||||
- No dependencies
|
- No dependencies
|
||||||
- Note: `lean4checker` uses a different version tagging scheme: use `toolchain/v4.6.0` rather than `v4.6.0`.
|
|
||||||
- Toolchain bump PR
|
- Toolchain bump PR
|
||||||
- Create and push the tag
|
- Create and push the tag
|
||||||
- Merge the tag into `stable`
|
- Merge the tag into `stable`
|
||||||
@@ -82,10 +79,8 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
|||||||
- Dependencies: `Aesop`, `ProofWidgets4`, `lean4checker`, `Batteries`, `doc-gen4`, `import-graph`
|
- Dependencies: `Aesop`, `ProofWidgets4`, `lean4checker`, `Batteries`, `doc-gen4`, `import-graph`
|
||||||
- Toolchain bump PR notes:
|
- Toolchain bump PR notes:
|
||||||
- In addition to updating the `lean-toolchain` and `lakefile.lean`,
|
- In addition to updating the `lean-toolchain` and `lakefile.lean`,
|
||||||
in `.github/workflows/build.yml.in` in the `lean4checker` section update the line
|
in `.github/workflows/lean4checker.yml` update the line
|
||||||
`git checkout toolchain/v4.6.0` to the appropriate tag,
|
`git checkout v4.6.0` to the appropriate tag.
|
||||||
and then run `.github/workflows/mk_build_yml.sh`. Coordinate with
|
|
||||||
a Mathlib maintainer to get this merged.
|
|
||||||
- Push the PR branch to the main Mathlib repository rather than a fork, or CI may not work reliably
|
- Push the PR branch to the main Mathlib repository rather than a fork, or CI may not work reliably
|
||||||
- Create and push the tag
|
- Create and push the tag
|
||||||
- Create a new branch from the tag, push it, and open a pull request against `stable`.
|
- Create a new branch from the tag, push it, and open a pull request against `stable`.
|
||||||
@@ -97,6 +92,10 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
|||||||
- Toolchain bump PR including updated Lake manifest
|
- Toolchain bump PR including updated Lake manifest
|
||||||
- Create and push the tag
|
- Create and push the tag
|
||||||
- Merge the tag into `stable`
|
- Merge the tag into `stable`
|
||||||
|
- The `v4.6.0` section of `RELEASES.md` is out of sync between
|
||||||
|
`releases/v4.6.0` and `master`. This should be reconciled:
|
||||||
|
- Replace the `v4.6.0` section on `master` with the `v4.6.0` section on `releases/v4.6.0`
|
||||||
|
and commit this to `master`.
|
||||||
- Merge the release announcement PR for the Lean website - it will be deployed automatically
|
- Merge the release announcement PR for the Lean website - it will be deployed automatically
|
||||||
- Finally, make an announcement!
|
- Finally, make an announcement!
|
||||||
This should go in https://leanprover.zulipchat.com/#narrow/stream/113486-announce, with topic `v4.6.0`.
|
This should go in https://leanprover.zulipchat.com/#narrow/stream/113486-announce, with topic `v4.6.0`.
|
||||||
@@ -107,7 +106,6 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
|||||||
|
|
||||||
## Optimistic(?) time estimates:
|
## Optimistic(?) time estimates:
|
||||||
- Initial checks and push the tag: 30 minutes.
|
- Initial checks and push the tag: 30 minutes.
|
||||||
- Note that if `RELEASES.md` has discrepancies this could take longer!
|
|
||||||
- Waiting for the release: 60 minutes.
|
- Waiting for the release: 60 minutes.
|
||||||
- Fixing release notes: 10 minutes.
|
- Fixing release notes: 10 minutes.
|
||||||
- Bumping toolchains in downstream repositories, up to creating the Mathlib PR: 30 minutes.
|
- Bumping toolchains in downstream repositories, up to creating the Mathlib PR: 30 minutes.
|
||||||
@@ -134,54 +132,52 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
|
|||||||
git checkout nightly-2024-02-29
|
git checkout nightly-2024-02-29
|
||||||
git checkout -b releases/v4.7.0
|
git checkout -b releases/v4.7.0
|
||||||
```
|
```
|
||||||
- In `RELEASES.md` remove `(development in progress)` from the `v4.7.0` section header.
|
- In `RELEASES.md` replace `Development in progress` in the `v4.7.0` section with `Release notes to be written.`
|
||||||
- Our current goal is to have written release notes only about major language features or breaking changes,
|
- We will rely on automatically generated release notes for release candidates,
|
||||||
and to rely on automatically generated release notes for bugfixes and minor changes.
|
and the written release notes will be used for stable versions only.
|
||||||
- Do not wait on `RELEASES.md` being perfect before creating the `release/v4.7.0` branch. It is essential to choose the nightly which will become the release candidate as early as possible, to avoid confusion.
|
It is essential to choose the nightly that will become the release candidate as early as possible, to avoid confusion.
|
||||||
- If there are major changes not reflected in `RELEASES.md` already, you may need to solicit help from the authors.
|
|
||||||
- Minor changes and bug fixes do not need to be documented in `RELEASES.md`: they will be added automatically on the Github release page.
|
|
||||||
- Commit your changes to `RELEASES.md`, and push.
|
|
||||||
- Remember that changes to `RELEASES.md` after you have branched `releases/v4.7.0` should also be cherry-picked back to `master`.
|
|
||||||
- In `src/CMakeLists.txt`,
|
- In `src/CMakeLists.txt`,
|
||||||
- verify that you see `set(LEAN_VERSION_MINOR 7)` (for whichever `7` is appropriate); this should already have been updated when the development cycle began.
|
- verify that you see `set(LEAN_VERSION_MINOR 7)` (for whichever `7` is appropriate); this should already have been updated when the development cycle began.
|
||||||
- `set(LEAN_VERSION_IS_RELEASE 1)` (this should be a change; on `master` and nightly releases it is always `0`).
|
- `set(LEAN_VERSION_IS_RELEASE 1)` (this should be a change; on `master` and nightly releases it is always `0`).
|
||||||
- Commit your changes to `src/CMakeLists.txt`, and push.
|
- Commit your changes to `src/CMakeLists.txt`, and push.
|
||||||
- `git tag v4.7.0-rc1`
|
- `git tag v4.7.0-rc1`
|
||||||
- `git push origin v4.7.0-rc1`
|
- `git push origin v4.7.0-rc1`
|
||||||
|
- Ping the FRO Zulip that release notes need to be written. The release notes do not block completing the rest of this checklist.
|
||||||
- Now wait, while CI runs.
|
- Now wait, while CI runs.
|
||||||
- You can monitor this at `https://github.com/leanprover/lean4/actions/workflows/ci.yml`, looking for the `v4.7.0-rc1` tag.
|
- You can monitor this at `https://github.com/leanprover/lean4/actions/workflows/ci.yml`, looking for the `v4.7.0-rc1` tag.
|
||||||
- This step can take up to an hour.
|
- This step can take up to an hour.
|
||||||
- Once the release appears at https://github.com/leanprover/lean4/releases/
|
- (GitHub release notes) Once the release appears at https://github.com/leanprover/lean4/releases/
|
||||||
- Edit the release notes on Github to select the "Set as a pre-release box".
|
- Verify that the release is marked as a prerelease (this should have been done automatically by the CI release job).
|
||||||
- Copy the section of `RELEASES.md` for this version into the Github release notes.
|
- In the "previous tag" dropdown, select `v4.6.0`, and click "Generate release notes".
|
||||||
- Use the title "Changes since v4.6.0 (from RELEASES.md)"
|
This will add a list of all the commits since the last stable version.
|
||||||
- Then in the "previous tag" dropdown, select `v4.6.0`, and click "Generate release notes".
|
|
||||||
- This will add a list of all the commits since the last stable version.
|
|
||||||
- Delete anything already mentioned in the hand-written release notes above.
|
|
||||||
- Delete "update stage0" commits, and anything with a completely inscrutable commit message.
|
- Delete "update stage0" commits, and anything with a completely inscrutable commit message.
|
||||||
- Briefly rearrange the remaining items by category (e.g. `simp`, `lake`, `bug fixes`),
|
|
||||||
but for minor items don't put any work in expanding on commit messages.
|
|
||||||
- (How we want to release notes to look is evolving: please update this section if it looks wrong!)
|
|
||||||
- Next, we will move a curated list of downstream repos to the release candidate.
|
- Next, we will move a curated list of downstream repos to the release candidate.
|
||||||
- This assumes that there is already a *reviewed* branch `bump/v4.7.0` on each repository
|
- This assumes that for each repository either:
|
||||||
containing the required adaptations (or no adaptations are required).
|
* There is already a *reviewed* branch `bump/v4.7.0` containing the required adaptations.
|
||||||
The preparation of this branch is beyond the scope of this document.
|
The preparation of this branch is beyond the scope of this document.
|
||||||
|
* The repository does not need any changes to move to the new version.
|
||||||
- For each of the target repositories:
|
- For each of the target repositories:
|
||||||
- Checkout the `bump/v4.7.0` branch.
|
- If the repository does not need any changes (i.e. `bump/v4.7.0` does not exist) then create
|
||||||
- Verify that the `lean-toolchain` is set to the nightly from which the release candidate was created.
|
a new PR updating `lean-toolchain` to `leanprover/lean4:v4.7.0-rc1` and running `lake update`.
|
||||||
- `git merge origin/master`
|
- Otherwise:
|
||||||
- Change the `lean-toolchain` to `leanprover/lean4:v4.7.0-rc1`
|
- Checkout the `bump/v4.7.0` branch.
|
||||||
- In `lakefile.lean`, change any dependencies which were using `nightly-testing` or `bump/v4.7.0` branches
|
- Verify that the `lean-toolchain` is set to the nightly from which the release candidate was created.
|
||||||
back to `master` or `main`, and run `lake update` for those dependencies.
|
- `git merge origin/master`
|
||||||
- Run `lake build` to ensure that dependencies are found (but it's okay to stop it after a moment).
|
- Change the `lean-toolchain` to `leanprover/lean4:v4.7.0-rc1`
|
||||||
- `git commit`
|
- In `lakefile.lean`, change any dependencies which were using `nightly-testing` or `bump/v4.7.0` branches
|
||||||
- `git push`
|
back to `master` or `main`, and run `lake update` for those dependencies.
|
||||||
- Open a PR from `bump/v4.7.0` to `master`, and either merge it yourself after CI, if appropriate,
|
- Run `lake build` to ensure that dependencies are found (but it's okay to stop it after a moment).
|
||||||
or notify the maintainers that it is ready to go.
|
- `git commit`
|
||||||
- Once this PR has been merged, tag `master` with `v4.7.0-rc1` and push this tag.
|
- `git push`
|
||||||
|
- Open a PR from `bump/v4.7.0` to `master`, and either merge it yourself after CI, if appropriate,
|
||||||
|
or notify the maintainers that it is ready to go.
|
||||||
|
- Once the PR has been merged, tag `master` with `v4.7.0-rc1` and push this tag.
|
||||||
- We do this for the same list of repositories as for stable releases, see above.
|
- We do this for the same list of repositories as for stable releases, see above.
|
||||||
As above, there are dependencies between these, and so the process above is iterative.
|
As above, there are dependencies between these, and so the process above is iterative.
|
||||||
It greatly helps if you can merge the `bump/v4.7.0` PRs yourself!
|
It greatly helps if you can merge the `bump/v4.7.0` PRs yourself!
|
||||||
|
It is essential for Mathlib CI that you then create the next `bump/v4.8.0` branch
|
||||||
|
for the next development cycle.
|
||||||
|
Set the `lean-toolchain` file on this branch to same `nightly` you used for this release.
|
||||||
- For Batteries/Aesop/Mathlib, which maintain a `nightly-testing` branch, make sure there is a tag
|
- For Batteries/Aesop/Mathlib, which maintain a `nightly-testing` branch, make sure there is a tag
|
||||||
`nightly-testing-2024-02-29` with date corresponding to the nightly used for the release
|
`nightly-testing-2024-02-29` with date corresponding to the nightly used for the release
|
||||||
(create it if not), and then on the `nightly-testing` branch `git reset --hard master`, and force push.
|
(create it if not), and then on the `nightly-testing` branch `git reset --hard master`, and force push.
|
||||||
@@ -192,8 +188,21 @@ We'll use `v4.7.0-rc1` as the intended release version in this example.
|
|||||||
Please also make sure that whoever is handling social media knows the release is out.
|
Please also make sure that whoever is handling social media knows the release is out.
|
||||||
- Begin the next development cycle (i.e. for `v4.8.0`) on the Lean repository, by making a PR that:
|
- Begin the next development cycle (i.e. for `v4.8.0`) on the Lean repository, by making a PR that:
|
||||||
- Updates `src/CMakeLists.txt` to say `set(LEAN_VERSION_MINOR 8)`
|
- Updates `src/CMakeLists.txt` to say `set(LEAN_VERSION_MINOR 8)`
|
||||||
- Removes `(in development)` from the section heading in `RELEASES.md` for `v4.7.0`,
|
- Replaces the "release notes will be copied" text in the `v4.6.0` section of `RELEASES.md` with the
|
||||||
and creates a new `v4.8.0 (in development)` section heading.
|
finalized release notes from the `releases/v4.6.0` branch.
|
||||||
|
- Replaces the "development in progress" in the `v4.7.0` section of `RELEASES.md` with
|
||||||
|
```
|
||||||
|
Release candidate, release notes will be copied from the branch `releases/v4.7.0` once completed.
|
||||||
|
```
|
||||||
|
and inserts the following section before that section:
|
||||||
|
```
|
||||||
|
v4.8.0
|
||||||
|
----------
|
||||||
|
Development in progress.
|
||||||
|
```
|
||||||
|
- Removes all the entries from the `./releases_drafts/` folder.
|
||||||
|
- Titled "chore: begin development cycle for v4.8.0"
|
||||||
|
|
||||||
|
|
||||||
## Time estimates:
|
## Time estimates:
|
||||||
Slightly longer than the corresponding steps for a stable release.
|
Slightly longer than the corresponding steps for a stable release.
|
||||||
@@ -218,12 +227,30 @@ Please read https://leanprover-community.github.io/contribute/tags_and_branches.
|
|||||||
* This can either be done by the person managing this process directly,
|
* This can either be done by the person managing this process directly,
|
||||||
or by soliciting assistance from authors of files, or generally helpful people on Zulip!
|
or by soliciting assistance from authors of files, or generally helpful people on Zulip!
|
||||||
* Each repo has a `bump/v4.7.0` which accumulates reviewed changes adapting to new versions.
|
* Each repo has a `bump/v4.7.0` which accumulates reviewed changes adapting to new versions.
|
||||||
* Once `nightly-testing` is working on a given nightly, say `nightly-2024-02-15`, we:
|
* Once `nightly-testing` is working on a given nightly, say `nightly-2024-02-15`, we will create a PR to `bump/v4.7.0`.
|
||||||
|
* For Mathlib, there is a script in `scripts/create-adaptation-pr.sh` that automates this process.
|
||||||
|
* For Batteries and Aesop it is currently manual.
|
||||||
|
* For all of these repositories, the process is the same:
|
||||||
* Make sure `bump/v4.7.0` is up to date with `master` (by merging `master`, no PR necessary)
|
* Make sure `bump/v4.7.0` is up to date with `master` (by merging `master`, no PR necessary)
|
||||||
* Create from `bump/v4.7.0` a `bump/nightly-2024-02-15` branch.
|
* Create from `bump/v4.7.0` a `bump/nightly-2024-02-15` branch.
|
||||||
* In that branch, `git merge --squash nightly-testing` to bring across changes from `nightly-testing`.
|
* In that branch, `git merge nightly-testing` to bring across changes from `nightly-testing`.
|
||||||
* Sanity check changes, commit, and make a PR to `bump/v4.7.0` from the `bump/nightly-2024-02-15` branch.
|
* Sanity check changes, commit, and make a PR to `bump/v4.7.0` from the `bump/nightly-2024-02-15` branch.
|
||||||
* Solicit review, merge the PR into `bump/v4,7,0`.
|
* Solicit review, merge the PR into `bump/v4.7.0`.
|
||||||
* It is always okay to merge in the following directions:
|
* It is always okay to merge in the following directions:
|
||||||
`master` -> `bump/v4.7.0` -> `bump/nightly-2024-02-15` -> `nightly-testing`.
|
`master` -> `bump/v4.7.0` -> `bump/nightly-2024-02-15` -> `nightly-testing`.
|
||||||
Please remember to push any merges you make to intermediate steps!
|
Please remember to push any merges you make to intermediate steps!
|
||||||
|
|
||||||
|
# Writing the release notes
|
||||||
|
|
||||||
|
We are currently trying a system where release notes are compiled all at once from someone looking through the commit history.
|
||||||
|
The exact steps are a work in progress.
|
||||||
|
Here is the general idea:
|
||||||
|
|
||||||
|
* The work is done right on the `releases/v4.6.0` branch sometime after it is created but before the stable release is made.
|
||||||
|
The release notes for `v4.6.0` will later be copied to `master` when we begin a new development cycle.
|
||||||
|
* There can be material for release notes entries in commit messages.
|
||||||
|
* There can also be pre-written entries in `./releases_drafts`, which should be all incorporated in the release notes and then deleted from the branch.
|
||||||
|
See `./releases_drafts/README.md` for more information.
|
||||||
|
* The release notes should be written from a downstream expert user's point of view.
|
||||||
|
|
||||||
|
This section will be updated when the next release notes are written (for `v4.10.0`).
|
||||||
|
|||||||
1
doc/examples/compiler/.gitignore
vendored
Normal file
1
doc/examples/compiler/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
build
|
||||||
@@ -149,4 +149,4 @@ def fact : Expr ctx (Ty.fn Ty.int Ty.int) :=
|
|||||||
(op (·*·) (delay fun _ => app fact (op (·-·) (var stop) (val 1))) (var stop)))
|
(op (·*·) (delay fun _ => app fact (op (·-·) (var stop) (val 1))) (var stop)))
|
||||||
decreasing_by sorry
|
decreasing_by sorry
|
||||||
|
|
||||||
#eval fact.interp Env.nil 10
|
#eval! fact.interp Env.nil 10
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
source ../../tests/common.sh
|
source ../../tests/common.sh
|
||||||
|
|
||||||
exec_check lean -j 0 -Dlinter.all=false "$f"
|
exec_check lean -Dlinter.all=false "$f"
|
||||||
|
|||||||
@@ -4,15 +4,18 @@ open Lean Widget
|
|||||||
/-!
|
/-!
|
||||||
# The user-widgets system
|
# The user-widgets system
|
||||||
|
|
||||||
Proving and programming are inherently interactive tasks. Lots of mathematical objects and data
|
Proving and programming are inherently interactive tasks.
|
||||||
structures are visual in nature. *User widgets* let you associate custom interactive UIs with
|
Lots of mathematical objects and data structures are visual in nature.
|
||||||
sections of a Lean document. User widgets are rendered in the Lean infoview.
|
*User widgets* let you associate custom interactive UIs
|
||||||
|
with sections of a Lean document.
|
||||||
|
User widgets are rendered in the Lean infoview.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Trying it out
|
## Trying it out
|
||||||
|
|
||||||
To try it out, simply type in the following code and place your cursor over the `#widget` command.
|
To try it out, type in the following code and place your cursor over the `#widget` command.
|
||||||
|
You can also [view this manual entry in the online editor](https://live.lean-lang.org/#url=https%3A%2F%2Fraw.githubusercontent.com%2Fleanprover%2Flean4%2Fmaster%2Fdoc%2Fexamples%2Fwidgets.lean).
|
||||||
-/
|
-/
|
||||||
|
|
||||||
@[widget_module]
|
@[widget_module]
|
||||||
@@ -21,38 +24,37 @@ def helloWidget : Widget.Module where
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
export default function(props) {
|
export default function(props) {
|
||||||
const name = props.name || 'world'
|
const name = props.name || 'world'
|
||||||
return React.createElement('p', {}, name + '!')
|
return React.createElement('p', {}, 'Hello ' + name + '!')
|
||||||
}"
|
}"
|
||||||
|
|
||||||
#widget helloWidget
|
#widget helloWidget
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
If you want to dive into a full sample right away, check out
|
If you want to dive into a full sample right away, check out
|
||||||
[`RubiksCube`](https://github.com/leanprover/lean4-samples/blob/main/RubiksCube/).
|
[`Rubiks`](https://github.com/leanprover-community/ProofWidgets4/blob/main/ProofWidgets/Demos/Rubiks.lean).
|
||||||
|
This sample uses higher-level widget components from the ProofWidgets library.
|
||||||
|
|
||||||
Below, we'll explain the system piece by piece.
|
Below, we'll explain the system piece by piece.
|
||||||
|
|
||||||
⚠️ WARNING: All of the user widget APIs are **unstable** and subject to breaking changes.
|
⚠️ WARNING: All of the user widget APIs are **unstable** and subject to breaking changes.
|
||||||
|
|
||||||
## Widget sources and instances
|
## Widget modules and instances
|
||||||
|
|
||||||
A *widget source* is a valid JavaScript [ESModule](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
|
A [widget module](https://leanprover-community.github.io/mathlib4_docs/Lean/Widget/UserWidget.html#Lean.Widget.Module)
|
||||||
which exports a [React component](https://reactjs.org/docs/components-and-props.html). To access
|
is a valid JavaScript [ESModule](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
|
||||||
React, the module must use `import * as React from 'react'`. Our first example of a widget source
|
that can execute in the Lean infoview.
|
||||||
is of course the value of `helloWidget.javascript`.
|
Most widget modules export a [React component](https://reactjs.org/docs/components-and-props.html)
|
||||||
|
as the piece of user interface to be rendered.
|
||||||
|
To access React, the module can use `import * as React from 'react'`.
|
||||||
|
Our first example of a widget module is `helloWidget` above.
|
||||||
|
Widget modules must be registered with the `@[widget_module]` attribute.
|
||||||
|
|
||||||
We can register a widget source with the `@[widget]` attribute, giving it a friendlier name
|
A [widget instance](https://leanprover-community.github.io/mathlib4_docs/Lean/Widget/Types.html#Lean.Widget.WidgetInstance)
|
||||||
in the `name` field. This is bundled together in a `UserWidgetDefinition`.
|
is then the identifier of a widget module (e.g. `` `helloWidget ``)
|
||||||
|
bundled with a value for its props.
|
||||||
A *widget instance* is then the identifier of a `UserWidgetDefinition` (so `` `helloWidget ``,
|
This value is passed as the argument to the React component.
|
||||||
not `"Hello"`) associated with a range of positions in the Lean source code. Widget instances
|
In our first invocation of `#widget`, we set it to `.null`.
|
||||||
are stored in the *infotree* in the same manner as other information about the source file
|
Try out what happens when you type in:
|
||||||
such as the type of every expression. In our example, the `#widget` command stores a widget instance
|
|
||||||
with the entire line as its range. We can think of a widget instance as an instruction for the
|
|
||||||
infoview: "when the user places their cursor here, please render the following widget".
|
|
||||||
|
|
||||||
Every widget instance also contains a `props : Json` value. This value is passed as an argument
|
|
||||||
to the React component. In our first invocation of `#widget`, we set it to `.null`. Try out what
|
|
||||||
happens when you type in:
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
structure HelloWidgetProps where
|
structure HelloWidgetProps where
|
||||||
@@ -62,21 +64,37 @@ structure HelloWidgetProps where
|
|||||||
#widget helloWidget with { name? := "<your name here>" : HelloWidgetProps }
|
#widget helloWidget with { name? := "<your name here>" : HelloWidgetProps }
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
💡 NOTE: The RPC system presented below does not depend on JavaScript. However the primary use case
|
Under the hood, widget instances are associated with a range of positions in the source file.
|
||||||
is the web-based infoview in VSCode.
|
Widget instances are stored in the *infotree*
|
||||||
|
in the same manner as other information about the source file
|
||||||
|
such as the type of every expression.
|
||||||
|
In our example, the `#widget` command stores a widget instance
|
||||||
|
with the entire line as its range.
|
||||||
|
One can think of the infotree entry as an instruction for the infoview:
|
||||||
|
"when the user places their cursor here, please render the following widget".
|
||||||
|
-/
|
||||||
|
|
||||||
|
/-!
|
||||||
## Querying the Lean server
|
## Querying the Lean server
|
||||||
|
|
||||||
Besides enabling us to create cool client-side visualizations, user widgets come with the ability
|
💡 NOTE: The RPC system presented below does not depend on JavaScript.
|
||||||
to communicate with the Lean server. Thanks to this, they have the same metaprogramming capabilities
|
However, the primary use case is the web-based infoview in VSCode.
|
||||||
as custom elaborators or the tactic framework. To see this in action, let's implement a `#check`
|
|
||||||
command as a web input form. This example assumes some familiarity with React.
|
|
||||||
|
|
||||||
The first thing we'll need is to create an *RPC method*. Meaning "Remote Procedure Call", this
|
Besides enabling us to create cool client-side visualizations,
|
||||||
is basically a Lean function callable from widget code (possibly remotely over the internet).
|
user widgets have the ability to communicate with the Lean server.
|
||||||
|
Thanks to this, they have the same metaprogramming capabilities
|
||||||
|
as custom elaborators or the tactic framework.
|
||||||
|
To see this in action, let's implement a `#check` command as a web input form.
|
||||||
|
This example assumes some familiarity with React.
|
||||||
|
|
||||||
|
The first thing we'll need is to create an *RPC method*.
|
||||||
|
Meaning "Remote Procedure Call",this is a Lean function callable from widget code
|
||||||
|
(possibly remotely over the internet).
|
||||||
Our method will take in the `name : Name` of a constant in the environment and return its type.
|
Our method will take in the `name : Name` of a constant in the environment and return its type.
|
||||||
By convention, we represent the input data as a `structure`. Since it will be sent over from JavaScript,
|
By convention, we represent the input data as a `structure`.
|
||||||
we need `FromJson` and `ToJson`. We'll see below why the position field is needed.
|
Since it will be sent over from JavaScript,
|
||||||
|
we need `FromJson` and `ToJson` instnace.
|
||||||
|
We'll see why the position field is needed later.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
structure GetTypeParams where
|
structure GetTypeParams where
|
||||||
@@ -87,25 +105,33 @@ structure GetTypeParams where
|
|||||||
deriving FromJson, ToJson
|
deriving FromJson, ToJson
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
After its arguments, we define the `getType` method. Every RPC method executes in the `RequestM`
|
After its argument structure, we define the `getType` method.
|
||||||
monad and must return a `RequestTask α` where `α` is its "actual" return type. The `Task` is so
|
RPCs method execute in the `RequestM` monad and must return a `RequestTask α`
|
||||||
that requests can be handled concurrently. A first guess for `α` might be `Expr`. However,
|
where `α` is the "actual" return type.
|
||||||
expressions in general can be large objects which depend on an `Environment` and `LocalContext`.
|
The `Task` is so that requests can be handled concurrently.
|
||||||
Thus we cannot directly serialize an `Expr` and send it to the widget. Instead, there are two
|
As a first guess, we'd use `Expr` as `α`.
|
||||||
options:
|
However, expressions in general can be large objects
|
||||||
- One is to send a *reference* which points to an object residing on the server. From JavaScript's
|
which depend on an `Environment` and `LocalContext`.
|
||||||
point of view, references are entirely opaque, but they can be sent back to other RPC methods for
|
Thus we cannot directly serialize an `Expr` and send it to JavaScript.
|
||||||
further processing.
|
Instead, there are two options:
|
||||||
- Two is to pretty-print the expression and send its textual representation called `CodeWithInfos`.
|
|
||||||
This representation contains extra data which the infoview uses for interactivity. We take this
|
|
||||||
strategy here.
|
|
||||||
|
|
||||||
RPC methods execute in the context of a file, but not any particular `Environment` so they don't
|
- One is to send a *reference* which points to an object residing on the server.
|
||||||
know about the available `def`initions and `theorem`s. Thus, we need to pass in a position at which
|
From JavaScript's point of view, references are entirely opaque,
|
||||||
we want to use the local `Environment`. This is why we store it in `GetTypeParams`. The `withWaitFindSnapAtPos`
|
but they can be sent back to other RPC methods for further processing.
|
||||||
method launches a concurrent computation whose job is to find such an `Environment` and a bit
|
- The other is to pretty-print the expression and send its textual representation called `CodeWithInfos`.
|
||||||
more information for us, in the form of a `snap : Snapshot`. With this in hand, we can call
|
This representation contains extra data which the infoview uses for interactivity.
|
||||||
`MetaM` procedures to find out the type of `name` and pretty-print it.
|
We take this strategy here.
|
||||||
|
|
||||||
|
RPC methods execute in the context of a file,
|
||||||
|
but not of any particular `Environment`,
|
||||||
|
so they don't know about the available `def`initions and `theorem`s.
|
||||||
|
Thus, we need to pass in a position at which we want to use the local `Environment`.
|
||||||
|
This is why we store it in `GetTypeParams`.
|
||||||
|
The `withWaitFindSnapAtPos` method launches a concurrent computation
|
||||||
|
whose job is to find such an `Environment` for us,
|
||||||
|
in the form of a `snap : Snapshot`.
|
||||||
|
With this in hand, we can call `MetaM` procedures
|
||||||
|
to find out the type of `name` and pretty-print it.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
open Server RequestM in
|
open Server RequestM in
|
||||||
@@ -121,18 +147,22 @@ def getType (params : GetTypeParams) : RequestM (RequestTask CodeWithInfos) :=
|
|||||||
/-!
|
/-!
|
||||||
## Using infoview components
|
## Using infoview components
|
||||||
|
|
||||||
Now that we have all we need on the server side, let's write the widget source. By importing
|
Now that we have all we need on the server side, let's write the widget module.
|
||||||
`@leanprover/infoview`, widgets can render UI components used to implement the infoview itself.
|
By importing `@leanprover/infoview`, widgets can render UI components used to implement the infoview itself.
|
||||||
For example, the `<InteractiveCode>` component displays expressions with `term : type` tooltips
|
For example, the `<InteractiveCode>` component displays expressions
|
||||||
as seen in the goal view. We will use it to implement our custom `#check` display.
|
with `term : type` tooltips as seen in the goal view.
|
||||||
|
We will use it to implement our custom `#check` display.
|
||||||
|
|
||||||
⚠️ WARNING: Like the other widget APIs, the infoview JS API is **unstable** and subject to breaking changes.
|
⚠️ WARNING: Like the other widget APIs, the infoview JS API is **unstable** and subject to breaking changes.
|
||||||
|
|
||||||
The code below demonstrates useful parts of the API. To make RPC method calls, we use the `RpcContext`.
|
The code below demonstrates useful parts of the API.
|
||||||
The `useAsync` helper packs the results of a call into an `AsyncState` structure which indicates
|
To make RPC method calls, we invoke the `useRpcSession` hook.
|
||||||
whether the call has resolved successfully, has returned an error, or is still in-flight. Based
|
The `useAsync` helper packs the results of an RPC call into an `AsyncState` structure
|
||||||
on this we either display an `InteractiveCode` with the type, `mapRpcError` the error in order
|
which indicates whether the call has resolved successfully,
|
||||||
to turn it into a readable message, or show a `Loading..` message, respectively.
|
has returned an error, or is still in-flight.
|
||||||
|
Based on this we either display an `InteractiveCode` component with the result,
|
||||||
|
`mapRpcError` the error in order to turn it into a readable message,
|
||||||
|
or show a `Loading..` message, respectively.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
@[widget_module]
|
@[widget_module]
|
||||||
@@ -140,10 +170,10 @@ def checkWidget : Widget.Module where
|
|||||||
javascript := "
|
javascript := "
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
const e = React.createElement;
|
const e = React.createElement;
|
||||||
import { RpcContext, InteractiveCode, useAsync, mapRpcError } from '@leanprover/infoview';
|
import { useRpcSession, InteractiveCode, useAsync, mapRpcError } from '@leanprover/infoview';
|
||||||
|
|
||||||
export default function(props) {
|
export default function(props) {
|
||||||
const rs = React.useContext(RpcContext)
|
const rs = useRpcSession()
|
||||||
const [name, setName] = React.useState('getType')
|
const [name, setName] = React.useState('getType')
|
||||||
|
|
||||||
const st = useAsync(() =>
|
const st = useAsync(() =>
|
||||||
@@ -159,7 +189,7 @@ export default function(props) {
|
|||||||
"
|
"
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
Finally we can try out the widget.
|
We can now try out the widget.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
#widget checkWidget
|
#widget checkWidget
|
||||||
@@ -169,30 +199,31 @@ Finally we can try out the widget.
|
|||||||
|
|
||||||
## Building widget sources
|
## Building widget sources
|
||||||
|
|
||||||
While typing JavaScript inline is fine for a simple example, for real developments we want to use
|
While typing JavaScript inline is fine for a simple example,
|
||||||
packages from NPM, a proper build system, and JSX. Thus, most actual widget sources are built with
|
for real developments we want to use packages from NPM, a proper build system, and JSX.
|
||||||
Lake and NPM. They consist of multiple files and may import libraries which don't work as ESModules
|
Thus, most actual widget sources are built with Lake and NPM.
|
||||||
by default. On the other hand a widget source must be a single, self-contained ESModule in the form
|
They consist of multiple files and may import libraries which don't work as ESModules by default.
|
||||||
of a string. Readers familiar with web development may already have guessed that to obtain such a
|
On the other hand a widget module must be a single, self-contained ESModule in the form of a string.
|
||||||
string, we need a *bundler*. Two popular choices are [`rollup.js`](https://rollupjs.org/guide/en/)
|
Readers familiar with web development may already have guessed that to obtain such a string, we need a *bundler*.
|
||||||
and [`esbuild`](https://esbuild.github.io/). If we go with `rollup.js`, to make a widget work with
|
Two popular choices are [`rollup.js`](https://rollupjs.org/guide/en/)
|
||||||
the infoview we need to:
|
and [`esbuild`](https://esbuild.github.io/).
|
||||||
|
If we go with `rollup.js`, to make a widget work with the infoview we need to:
|
||||||
- Set [`output.format`](https://rollupjs.org/guide/en/#outputformat) to `'es'`.
|
- Set [`output.format`](https://rollupjs.org/guide/en/#outputformat) to `'es'`.
|
||||||
- [Externalize](https://rollupjs.org/guide/en/#external) `react`, `react-dom`, `@leanprover/infoview`.
|
- [Externalize](https://rollupjs.org/guide/en/#external) `react`, `react-dom`, `@leanprover/infoview`.
|
||||||
These libraries are already loaded by the infoview so they should not be bundled.
|
These libraries are already loaded by the infoview so they should not be bundled.
|
||||||
|
|
||||||
In the RubiksCube sample, we provide a working `rollup.js` build configuration in
|
ProofWidgets provides a working `rollup.js` build configuration in
|
||||||
[rollup.config.js](https://github.com/leanprover/lean4-samples/blob/main/RubiksCube/widget/rollup.config.js).
|
[rollup.config.js](https://github.com/leanprover-community/ProofWidgets4/blob/main/widget/rollup.config.js).
|
||||||
|
|
||||||
## Inserting text
|
## Inserting text
|
||||||
|
|
||||||
We can also instruct the editor to insert text, copy text to the clipboard, or
|
Besides making RPC calls, widgets can instruct the editor to carry out certain actions.
|
||||||
reveal a certain location in the document.
|
We can insert text, copy text to the clipboard, or highlight a certain location in the document.
|
||||||
To do this, use the `React.useContext(EditorContext)` React context.
|
To do this, use the `EditorContext` React context.
|
||||||
This will return an `EditorConnection` whose `api` field contains a number of methods to
|
This will return an `EditorConnection`
|
||||||
interact with the text editor.
|
whose `api` field contains a number of methods that interact with the editor.
|
||||||
|
|
||||||
You can see the full API for this [here](https://github.com/leanprover/vscode-lean4/blob/master/lean4-infoview-api/src/infoviewApi.ts#L52)
|
The full API can be viewed [here](https://github.com/leanprover/vscode-lean4/blob/master/lean4-infoview-api/src/infoviewApi.ts#L52).
|
||||||
-/
|
-/
|
||||||
|
|
||||||
@[widget_module]
|
@[widget_module]
|
||||||
@@ -212,6 +243,4 @@ export default function(props) {
|
|||||||
}
|
}
|
||||||
"
|
"
|
||||||
|
|
||||||
/-! Finally, we can try this out: -/
|
|
||||||
|
|
||||||
#widget insertTextWidget
|
#widget insertTextWidget
|
||||||
|
|||||||
138
doc/flake.lock
generated
138
doc/flake.lock
generated
@@ -18,12 +18,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1656928814,
|
"lastModified": 1710146030,
|
||||||
"narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=",
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249",
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -35,13 +38,12 @@
|
|||||||
"lean": {
|
"lean": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"lean4-mode": "lean4-mode",
|
"nixpkgs": "nixpkgs",
|
||||||
"nix": "nix",
|
"nixpkgs-old": "nixpkgs-old"
|
||||||
"nixpkgs": "nixpkgs_2"
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 0,
|
"lastModified": 0,
|
||||||
"narHash": "sha256-YnYbmG0oou1Q/GE4JbMNb8/yqUVXBPIvcdQQJHBqtPk=",
|
"narHash": "sha256-saRAtQ6VautVXKDw1XH35qwP0KEBKTKZbg/TRa4N9Vw=",
|
||||||
"path": "../.",
|
"path": "../.",
|
||||||
"type": "path"
|
"type": "path"
|
||||||
},
|
},
|
||||||
@@ -50,22 +52,6 @@
|
|||||||
"type": "path"
|
"type": "path"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lean4-mode": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1659020985,
|
|
||||||
"narHash": "sha256-+dRaXB7uvN/weSZiKcfSKWhcdJVNg9Vg8k0pJkDNjpc=",
|
|
||||||
"owner": "leanprover",
|
|
||||||
"repo": "lean4-mode",
|
|
||||||
"rev": "37d5c99b7b29c80ab78321edd6773200deb0bca6",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "leanprover",
|
|
||||||
"repo": "lean4-mode",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"leanInk": {
|
"leanInk": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -83,22 +69,6 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lowdown-src": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1633514407,
|
|
||||||
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
|
|
||||||
"owner": "kristapsdz",
|
|
||||||
"repo": "lowdown",
|
|
||||||
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "kristapsdz",
|
|
||||||
"repo": "lowdown",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"mdBook": {
|
"mdBook": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -115,65 +85,13 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nix": {
|
|
||||||
"inputs": {
|
|
||||||
"lowdown-src": "lowdown-src",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"nixpkgs-regression": "nixpkgs-regression"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1657097207,
|
|
||||||
"narHash": "sha256-SmeGmjWM3fEed3kQjqIAO8VpGmkC2sL1aPE7kKpK650=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nix",
|
|
||||||
"rev": "f6316b49a0c37172bca87ede6ea8144d7d89832f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1653988320,
|
"lastModified": 1710889954,
|
||||||
"narHash": "sha256-ZaqFFsSDipZ6KVqriwM34T739+KLYJvNmCWzErjAg7c=",
|
"narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "2fa57ed190fd6c7c746319444f34b5917666e5c1",
|
"rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b",
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixos-22.05-small",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs-regression": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1643052045,
|
|
||||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1657208011,
|
|
||||||
"narHash": "sha256-BlIFwopAykvdy1DYayEkj6ZZdkn+cVgPNX98QVLc0jM=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "2770cc0b1e8faa0e20eb2c6aea64c256a706d4f2",
|
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -183,6 +101,23 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-old": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1581379743,
|
||||||
|
"narHash": "sha256-i1XCn9rKuLjvCdu2UeXKzGLF6IuQePQKFt4hEKRU5oc=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "34c7eb7545d155cc5b6f499b23a7cb1c96ab4d59",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-19.03",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"alectryon": "alectryon",
|
"alectryon": "alectryon",
|
||||||
@@ -194,6 +129,21 @@
|
|||||||
"leanInk": "leanInk",
|
"leanInk": "leanInk",
|
||||||
"mdBook": "mdBook"
|
"mdBook": "mdBook"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
outputs = inputs@{ self, ... }: inputs.flake-utils.lib.eachDefaultSystem (system:
|
outputs = inputs@{ self, ... }: inputs.flake-utils.lib.eachDefaultSystem (system:
|
||||||
with inputs.lean.packages.${system}; with nixpkgs;
|
with inputs.lean.packages.${system}.deprecated; with nixpkgs;
|
||||||
let
|
let
|
||||||
doc-src = lib.sourceByRegex ../. ["doc.*" "tests(/lean(/beginEndAsMacro.lean)?)?"];
|
doc-src = lib.sourceByRegex ../. ["doc.*" "tests(/lean(/beginEndAsMacro.lean)?)?"];
|
||||||
in {
|
in {
|
||||||
@@ -44,21 +44,6 @@
|
|||||||
mdbook build -d $out
|
mdbook build -d $out
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
# We use a separate derivation instead of `checkPhase` so we can push it but not `doc` to the binary cache
|
|
||||||
test = stdenv.mkDerivation {
|
|
||||||
name ="lean-doc-test";
|
|
||||||
src = doc-src;
|
|
||||||
buildInputs = [ lean-mdbook stage1.Lean.lean-package strace ];
|
|
||||||
patchPhase = ''
|
|
||||||
cd doc
|
|
||||||
patchShebangs test
|
|
||||||
'';
|
|
||||||
buildPhase = ''
|
|
||||||
mdbook test
|
|
||||||
touch $out
|
|
||||||
'';
|
|
||||||
dontInstall = true;
|
|
||||||
};
|
|
||||||
leanInk = (buildLeanPackage {
|
leanInk = (buildLeanPackage {
|
||||||
name = "Main";
|
name = "Main";
|
||||||
src = inputs.leanInk;
|
src = inputs.leanInk;
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 65 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 33 KiB |
@@ -13,7 +13,7 @@ Recall that nonnegative numerals are considered to be a `Nat` if there are no ty
|
|||||||
|
|
||||||
The operator `/` for `Int` implements integer division.
|
The operator `/` for `Int` implements integer division.
|
||||||
```lean
|
```lean
|
||||||
#eval -10 / 4 -- -2
|
#eval -10 / 4 -- -3
|
||||||
```
|
```
|
||||||
|
|
||||||
Similar to `Nat`, the internal representation of `Int` is optimized. Small integers are
|
Similar to `Nat`, the internal representation of `Int` is optimized. Small integers are
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
pygments.lexers.theorem
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Lexers for theorem-proving languages.
|
|
||||||
|
|
||||||
:copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS.
|
|
||||||
:license: BSD, see LICENSE for details.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import re
|
|
||||||
|
|
||||||
from pygments.lexer import RegexLexer, default, words
|
|
||||||
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
|
|
||||||
Number, Punctuation, Generic
|
|
||||||
|
|
||||||
__all__ = ['Lean4Lexer']
|
|
||||||
|
|
||||||
class Lean4Lexer(RegexLexer):
|
|
||||||
"""
|
|
||||||
For the `Lean 4 <https://github.com/leanprover/lean4>`_
|
|
||||||
theorem prover.
|
|
||||||
|
|
||||||
.. versionadded:: 2.0
|
|
||||||
"""
|
|
||||||
name = 'Lean4'
|
|
||||||
aliases = ['lean4']
|
|
||||||
filenames = ['*.lean']
|
|
||||||
mimetypes = ['text/x-lean']
|
|
||||||
|
|
||||||
flags = re.MULTILINE | re.UNICODE
|
|
||||||
|
|
||||||
keywords1 = (
|
|
||||||
'import', 'abbreviation', 'opaque_hint', 'tactic_hint', 'definition',
|
|
||||||
'renaming', 'inline', 'hiding', 'parameter', 'lemma', 'variable',
|
|
||||||
'theorem', 'axiom', 'inductive', 'structure', 'universe', 'alias',
|
|
||||||
'help', 'options', 'precedence', 'postfix', 'prefix',
|
|
||||||
'infix', 'infixl', 'infixr', 'notation', '#eval',
|
|
||||||
'#check', '#reduce', '#exit', 'coercion', 'end', 'private', 'using', 'namespace',
|
|
||||||
'including', 'instance', 'section', 'context', 'protected', 'expose',
|
|
||||||
'export', 'set_option', 'extends', 'open', 'example',
|
|
||||||
'constant', 'constants', 'print', 'opaque', 'reducible', 'irreducible',
|
|
||||||
'def', 'macro', 'elab', 'syntax', 'macro_rules', 'reduce', 'where',
|
|
||||||
'abbrev', 'noncomputable', 'class', 'attribute', 'synth', 'mutual',
|
|
||||||
)
|
|
||||||
|
|
||||||
keywords2 = (
|
|
||||||
'forall', 'fun', 'Pi', 'obtain', 'from', 'have', 'show', 'assume',
|
|
||||||
'take', 'let', 'if', 'else', 'then', 'by', 'in', 'with', 'begin',
|
|
||||||
'proof', 'qed', 'calc', 'match', 'nomatch', 'do', 'at',
|
|
||||||
)
|
|
||||||
|
|
||||||
keywords3 = (
|
|
||||||
# Sorts
|
|
||||||
'Type', 'Prop', 'Sort',
|
|
||||||
)
|
|
||||||
|
|
||||||
operators = (
|
|
||||||
u'!=', u'#', u'&', u'&&', u'*', u'+', u'-', u'/', u'@', u'!', u'`',
|
|
||||||
u'-.', u'->', u'.', u'..', u'...', u'::', u':>', u';', u';;', u'<',
|
|
||||||
u'<-', u'=', u'==', u'>', u'_', u'|', u'||', u'~', u'=>', u'<=', u'>=',
|
|
||||||
u'/\\', u'\\/', u'∀', u'Π', u'λ', u'↔', u'∧', u'∨', u'≠', u'≤', u'≥',
|
|
||||||
u'¬', u'⁻¹', u'⬝', u'▸', u'→', u'∃', u'ℕ', u'ℤ', u'≈', u'×', u'⌞',
|
|
||||||
u'⌟', u'≡', u'⟨', u'⟩',
|
|
||||||
)
|
|
||||||
|
|
||||||
punctuation = (u'(', u')', u':', u'{', u'}', u'[', u']', u'⦃', u'⦄',
|
|
||||||
u':=', u',')
|
|
||||||
|
|
||||||
tokens = {
|
|
||||||
'root': [
|
|
||||||
(r'\s+', Text),
|
|
||||||
(r'/-', Comment, 'comment'),
|
|
||||||
(r'--.*?$', Comment.Single),
|
|
||||||
(words(keywords1, prefix=r'\b', suffix=r'\b'), Keyword.Namespace),
|
|
||||||
(words(keywords2, prefix=r'\b', suffix=r'\b'), Keyword),
|
|
||||||
(words(keywords3, prefix=r'\b', suffix=r'\b'), Keyword.Type),
|
|
||||||
(words(operators), Name.Builtin.Pseudo),
|
|
||||||
(words(punctuation), Operator),
|
|
||||||
(u"[A-Za-z_\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2100-\u214f]"
|
|
||||||
u"[A-Za-z_'\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2070-\u2079"
|
|
||||||
u"\u207f-\u2089\u2090-\u209c\u2100-\u214f0-9]*", Name),
|
|
||||||
(r'\d+', Number.Integer),
|
|
||||||
(r'"', String.Double, 'string'),
|
|
||||||
(r'[~?][a-z][\w\']*:', Name.Variable)
|
|
||||||
],
|
|
||||||
'comment': [
|
|
||||||
# Multiline Comments
|
|
||||||
(r'[^/-]', Comment.Multiline),
|
|
||||||
(r'/-', Comment.Multiline, '#push'),
|
|
||||||
(r'-/', Comment.Multiline, '#pop'),
|
|
||||||
(r'[/-]', Comment.Multiline)
|
|
||||||
],
|
|
||||||
'string': [
|
|
||||||
(r'[^\\"]+', String.Double),
|
|
||||||
(r'\\[n"\\]', String.Escape),
|
|
||||||
('"', String.Double, '#pop'),
|
|
||||||
],
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
|
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](doc/dev/index.md).
|
||||||
|
|
||||||
|
We strongly suggest that new users instead follow the [Quickstart](doc/quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
|
||||||
|
|
||||||
Requirements
|
Requirements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
- C++14 compatible compiler
|
- C++14 compatible compiler
|
||||||
- [CMake](http://www.cmake.org)
|
- [CMake](http://www.cmake.org)
|
||||||
- [GMP (GNU multiprecision library)](http://gmplib.org/)
|
- [GMP (GNU multiprecision library)](http://gmplib.org/)
|
||||||
|
- [LibUV](https://libuv.org/)
|
||||||
|
|
||||||
Platform-Specific Setup
|
Platform-Specific Setup
|
||||||
-----------------------
|
-----------------------
|
||||||
@@ -17,39 +22,27 @@ Platform-Specific Setup
|
|||||||
Generic Build Instructions
|
Generic Build Instructions
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
Setting up a basic release build:
|
Setting up a basic parallelized release build:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/leanprover/lean4 --recurse-submodules
|
git clone https://github.com/leanprover/lean4
|
||||||
cd lean4
|
cd lean4
|
||||||
mkdir -p build/release
|
cmake --preset release
|
||||||
cd build/release
|
make -C build/release -j$(nproc || sysctl -n hw.logicalcpu)
|
||||||
cmake ../..
|
|
||||||
make
|
|
||||||
```
|
```
|
||||||
|
You can replace `$(nproc || sysctl -n hw.logicalcpu)` with the desired parallelism amount.
|
||||||
For regular development, we recommend running
|
|
||||||
```bash
|
|
||||||
git config submodule.recurse true
|
|
||||||
```
|
|
||||||
in the checkout so that `--recurse-submodules` doesn't have to be
|
|
||||||
specified with `git pull/checkout/...`.
|
|
||||||
|
|
||||||
The above commands will compile the Lean library and binaries into the
|
The above commands will compile the Lean library and binaries into the
|
||||||
`stage1` subfolder; see below for details. Add `-j N` for an
|
`stage1` subfolder; see below for details.
|
||||||
appropriate `N` to `make` for a parallel build.
|
|
||||||
|
|
||||||
For example, on an AMD Ryzen 9 `make` takes 00:04:55, whereas `make -j 10`
|
You should not usually run `cmake --install` after a successful build.
|
||||||
takes 00:01:38. Your results may vary depending on the speed of your hard
|
|
||||||
drive.
|
|
||||||
|
|
||||||
You should not usually run `make install` after a successful build.
|
|
||||||
See [Dev setup using elan](../dev/index.md#dev-setup-using-elan) on how to properly set up your editor to use the correct stage depending on the source directory.
|
See [Dev setup using elan](../dev/index.md#dev-setup-using-elan) on how to properly set up your editor to use the correct stage depending on the source directory.
|
||||||
|
|
||||||
Useful CMake Configuration Settings
|
Useful CMake Configuration Settings
|
||||||
-----------------------------------
|
-----------------------------------
|
||||||
|
|
||||||
Pass these along with the `cmake ../..` command.
|
Pass these along with the `cmake --preset release` command.
|
||||||
|
There are also two alternative presets that combine some of these options you can use instead of `release`: `debug` and `sandebug` (sanitize + debug).
|
||||||
|
|
||||||
* `-D CMAKE_BUILD_TYPE=`\
|
* `-D CMAKE_BUILD_TYPE=`\
|
||||||
Select the build type. Valid values are `RELEASE` (default), `DEBUG`,
|
Select the build type. Valid values are `RELEASE` (default), `DEBUG`,
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
# Compiling Lean with Visual Studio
|
|
||||||
|
|
||||||
WARNING: Compiling Lean with Visual Studio doesn't currently work.
|
|
||||||
There's an ongoing effort to port Lean to Visual Studio.
|
|
||||||
The instructions below are for VS 2017.
|
|
||||||
|
|
||||||
In the meantime you can use [MSYS2](msys2.md) or [WSL](wsl.md).
|
|
||||||
|
|
||||||
## Installing dependencies
|
|
||||||
|
|
||||||
First, install `vcpkg` from https://github.com/Microsoft/vcpkg if you haven't
|
|
||||||
done so already.
|
|
||||||
Then, open a console in the directory you cloned `vcpkg` to, and type:
|
|
||||||
`vcpkg install mpir` for the 32-bit library or
|
|
||||||
`vcpkg install mpir:x64-windows` for the x64 one.
|
|
||||||
|
|
||||||
In Visual Studio, use the "open folder" feature and open the Lean directory.
|
|
||||||
Go to the `CMake->Change CMake Settings` menu. File `CMakeSettings.json` opens.
|
|
||||||
In each of the targets, add the following snippet (i.e., after every
|
|
||||||
`ctestCommandArgs`):
|
|
||||||
|
|
||||||
```json
|
|
||||||
"variables": [
|
|
||||||
{
|
|
||||||
"name": "CMAKE_TOOLCHAIN_FILE",
|
|
||||||
"value": "C:\\path\\to\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Enable Intellisense
|
|
||||||
|
|
||||||
In Visual Studio, press Ctrl+Q and type `CppProperties.json` and press Enter.
|
|
||||||
Ensure `includePath` variables include `"${workspaceRoot}\\src"`.
|
|
||||||
|
|
||||||
|
|
||||||
## Build Lean
|
|
||||||
|
|
||||||
Press F7.
|
|
||||||
@@ -25,7 +25,7 @@ MSYS2 has a package management system, [pacman][pacman], which is used in Arch L
|
|||||||
Here are the commands to install all dependencies needed to compile Lean on your machine.
|
Here are the commands to install all dependencies needed to compile Lean on your machine.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pacman -S make python mingw-w64-x86_64-cmake mingw-w64-x86_64-clang mingw-w64-x86_64-ccache git unzip diffutils binutils
|
pacman -S make python mingw-w64-x86_64-cmake mingw-w64-x86_64-clang mingw-w64-x86_64-ccache mingw-w64-x86_64-libuv mingw-w64-x86_64-gmp git unzip diffutils binutils
|
||||||
```
|
```
|
||||||
|
|
||||||
You should now be able to run these commands:
|
You should now be able to run these commands:
|
||||||
@@ -38,10 +38,9 @@ cmake --version
|
|||||||
Then follow the [generic build instructions](index.md) in the MSYS2
|
Then follow the [generic build instructions](index.md) in the MSYS2
|
||||||
MinGW shell, using:
|
MinGW shell, using:
|
||||||
```
|
```
|
||||||
cmake ../.. -G "Unix Makefiles" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
cmake --preset release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||||
```
|
```
|
||||||
instead of `cmake ../..`. This ensures that cmake will call `sh` instead of `cmd.exe`
|
instead of `cmake --preset release`. This will use the clang compiler instead of gcc, which is required with msys2.
|
||||||
for script tasks and it will use the clang compiler instead of gcc, which is required.
|
|
||||||
|
|
||||||
## Install lean
|
## Install lean
|
||||||
|
|
||||||
@@ -65,6 +64,7 @@ they are installed in your MSYS setup:
|
|||||||
- libgcc_s_seh-1.dll
|
- libgcc_s_seh-1.dll
|
||||||
- libstdc++-6.dll
|
- libstdc++-6.dll
|
||||||
- libgmp-10.dll
|
- libgmp-10.dll
|
||||||
|
- libuv-1.dll
|
||||||
- libwinpthread-1.dll
|
- libwinpthread-1.dll
|
||||||
|
|
||||||
The following linux command will do that:
|
The following linux command will do that:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Install Packages on OS X 10.9
|
# Install Packages on OS X 14.5
|
||||||
|
|
||||||
We assume that you are using [homebrew][homebrew] as a package manager.
|
We assume that you are using [homebrew][homebrew] as a package manager.
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ brew install gcc
|
|||||||
```
|
```
|
||||||
To install clang++-3.5 via homebrew, please execute:
|
To install clang++-3.5 via homebrew, please execute:
|
||||||
```bash
|
```bash
|
||||||
brew install llvm --with-clang --with-asan
|
brew install llvm
|
||||||
```
|
```
|
||||||
To use compilers other than the default one (Apple's clang++), you
|
To use compilers other than the default one (Apple's clang++), you
|
||||||
need to use `-DCMAKE_CXX_COMPILER` option to specify the compiler
|
need to use `-DCMAKE_CXX_COMPILER` option to specify the compiler
|
||||||
@@ -32,15 +32,16 @@ following to use `g++`.
|
|||||||
cmake -DCMAKE_CXX_COMPILER=g++ ...
|
cmake -DCMAKE_CXX_COMPILER=g++ ...
|
||||||
```
|
```
|
||||||
|
|
||||||
## Required Packages: CMake, GMP
|
## Required Packages: CMake, GMP, libuv
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install cmake
|
brew install cmake
|
||||||
brew install gmp
|
brew install gmp
|
||||||
|
brew install libuv
|
||||||
```
|
```
|
||||||
|
|
||||||
## Recommended Packages: CCache
|
## Recommended Packages: CCache
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
brew install ccache
|
brew install ccache
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ follow the [generic build instructions](index.md).
|
|||||||
## Basic packages
|
## Basic packages
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt-get install git libgmp-dev cmake ccache clang
|
sudo apt-get install git libgmp-dev libuv1-dev cmake ccache clang
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -5,14 +5,19 @@ See [Setup](./setup.md) for supported platforms and other ways to set up Lean 4.
|
|||||||
|
|
||||||
1. Install [VS Code](https://code.visualstudio.com/).
|
1. Install [VS Code](https://code.visualstudio.com/).
|
||||||
|
|
||||||
1. Launch VS Code and install the `lean4` extension by clicking on the "Extensions" sidebar entry and searching for "lean4".
|
1. Launch VS Code and install the `Lean 4` extension by clicking on the 'Extensions' sidebar entry and searching for 'Lean 4'.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
1. Open the Lean 4 setup guide by creating a new text file using "File > New Text File" (`Ctrl+N`), clicking on the ∀-symbol in the top right and selecting "Documentation… > Setup: Show Setup Guide".
|
1. Open the Lean 4 setup guide by creating a new text file using 'File > New Text File' (`Ctrl+N` / `Cmd+N`), clicking on the ∀-symbol in the top right and selecting 'Documentation… > Docs: Show Setup Guide'.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
1. Follow the Lean 4 setup guide. It will walk you through learning resources for Lean 4, teach you how to set up Lean's dependencies on your platform, install Lean 4 for you at the click of a button and help you set up your first project.
|
1. Follow the Lean 4 setup guide. It will:
|
||||||
|
|
||||||

|
- walk you through learning resources for Lean,
|
||||||
|
- teach you how to set up Lean's dependencies on your platform,
|
||||||
|
- install Lean 4 for you at the click of a button,
|
||||||
|
- help you set up your first project.
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Platforms built & tested by our CI, available as binary releases via elan (see b
|
|||||||
|
|
||||||
* x86-64 Linux with glibc 2.27+
|
* x86-64 Linux with glibc 2.27+
|
||||||
* x86-64 macOS 10.15+
|
* x86-64 macOS 10.15+
|
||||||
|
* aarch64 (Apple Silicon) macOS 10.15+
|
||||||
* x86-64 Windows 10+
|
* x86-64 Windows 10+
|
||||||
|
|
||||||
### Tier 2
|
### Tier 2
|
||||||
@@ -16,7 +17,6 @@ Releases may be silently broken due to the lack of automated testing.
|
|||||||
Issue reports and fixes are welcome.
|
Issue reports and fixes are welcome.
|
||||||
|
|
||||||
* aarch64 Linux with glibc 2.27+
|
* aarch64 Linux with glibc 2.27+
|
||||||
* aarch64 (Apple Silicon) macOS
|
|
||||||
* x86 (32-bit) Linux
|
* x86 (32-bit) Linux
|
||||||
* Emscripten Web Assembly
|
* Emscripten Web Assembly
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ $ pdflatex test.tex
|
|||||||
|
|
||||||
## Example with `minted`
|
## Example with `minted`
|
||||||
|
|
||||||
First [install Pygments](https://pygments.org/download/). Then save [`lean4.py`](https://raw.githubusercontent.com/leanprover/lean4/master/doc/latex/lean4.py), which contains an version of the Lean highlighter updated for Lean 4, and the following sample LaTeX file `test.tex` into the same directory:
|
First [install Pygments](https://pygments.org/download/) (version 2.18 or newer).
|
||||||
|
Then save the following sample LaTeX file `test.tex` into the same directory:
|
||||||
|
|
||||||
```latex
|
```latex
|
||||||
\documentclass{article}
|
\documentclass{article}
|
||||||
@@ -51,9 +52,8 @@ First [install Pygments](https://pygments.org/download/). Then save [`lean4.py`]
|
|||||||
% switch to a monospace font supporting more Unicode characters
|
% switch to a monospace font supporting more Unicode characters
|
||||||
\setmonofont{FreeMono}
|
\setmonofont{FreeMono}
|
||||||
\usepackage{minted}
|
\usepackage{minted}
|
||||||
% instruct minted to use our local theorem.py
|
\newmintinline[lean]{lean4}{bgcolor=white}
|
||||||
\newmintinline[lean]{lean4.py:Lean4Lexer -x}{bgcolor=white}
|
\newminted[leancode]{lean4}{fontsize=\footnotesize}
|
||||||
\newminted[leancode]{lean4.py:Lean4Lexer -x}{fontsize=\footnotesize}
|
|
||||||
\usemintedstyle{tango} % a nice, colorful theme
|
\usemintedstyle{tango} % a nice, colorful theme
|
||||||
|
|
||||||
\begin{document}
|
\begin{document}
|
||||||
@@ -67,9 +67,6 @@ theorem funext {f₁ f₂ : ∀ (x : α), β x} (h : ∀ x, f₁ x = f₂ x) : f
|
|||||||
\end{document}
|
\end{document}
|
||||||
```
|
```
|
||||||
|
|
||||||
If your version of `minted` is v2.7 or newer, but before v3.0,
|
|
||||||
you will additionally need to follow the workaround described in https://github.com/gpoore/minted/issues/360.
|
|
||||||
|
|
||||||
You can then compile `test.tex` by executing the following command:
|
You can then compile `test.tex` by executing the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -81,11 +78,14 @@ Some remarks:
|
|||||||
- either `xelatex` or `lualatex` is required to handle Unicode characters in the code.
|
- either `xelatex` or `lualatex` is required to handle Unicode characters in the code.
|
||||||
- `--shell-escape` is needed to allow `xelatex` to execute `pygmentize` in a shell.
|
- `--shell-escape` is needed to allow `xelatex` to execute `pygmentize` in a shell.
|
||||||
- If the chosen monospace font is missing some Unicode symbols, you can direct them to be displayed using a fallback font or other replacement LaTeX code.
|
- If the chosen monospace font is missing some Unicode symbols, you can direct them to be displayed using a fallback font or other replacement LaTeX code.
|
||||||
``` latex
|
``` latex
|
||||||
\usepackage{newunicodechar}
|
\usepackage{newunicodechar}
|
||||||
\newfontfamily{\freeserif}{DejaVu Sans}
|
\newfontfamily{\freeserif}{DejaVu Sans}
|
||||||
\newunicodechar{✝}{\freeserif{✝}}
|
\newunicodechar{✝}{\freeserif{✝}}
|
||||||
\newunicodechar{𝓞}{\ensuremath{\mathcal{O}}}
|
\newunicodechar{𝓞}{\ensuremath{\mathcal{O}}}
|
||||||
```
|
```
|
||||||
- minted has a "helpful" feature that draws red boxes around characters the chosen lexer doesn't recognize.
|
- If you are using an old version of Pygments, you can copy
|
||||||
Since the Lean lexer cannot encompass all user-defined syntax, it is advisable to [work around](https://tex.stackexchange.com/a/343506/14563) this feature.
|
[`lean.py`](https://raw.githubusercontent.com/pygments/pygments/master/pygments/lexers/lean.py) into your working directory,
|
||||||
|
and use `lean4.py:Lean4Lexer -x` instead of `lean4` above.
|
||||||
|
If your version of `minted` is v2.7 or newer, but before v3.0,
|
||||||
|
you will additionally need to follow the workaround described in https://github.com/gpoore/minted/issues/360.
|
||||||
|
|||||||
130
flake.lock
generated
130
flake.lock
generated
@@ -1,21 +1,5 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"flake-compat": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1673956053,
|
|
||||||
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "edolstra",
|
|
||||||
"repo": "flake-compat",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
@@ -34,75 +18,38 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lean4-mode": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1709737301,
|
|
||||||
"narHash": "sha256-uT9JN2kLNKJK9c/S/WxLjiHmwijq49EgLb+gJUSDpz0=",
|
|
||||||
"owner": "leanprover",
|
|
||||||
"repo": "lean4-mode",
|
|
||||||
"rev": "f1f24c15134dee3754b82c9d9924866fe6bc6b9f",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "leanprover",
|
|
||||||
"repo": "lean4-mode",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"libgit2": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1697646580,
|
|
||||||
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
|
|
||||||
"owner": "libgit2",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "libgit2",
|
|
||||||
"repo": "libgit2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-compat": "flake-compat",
|
|
||||||
"libgit2": "libgit2",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"nixpkgs-regression": "nixpkgs-regression"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1711102798,
|
|
||||||
"narHash": "sha256-CXOIJr8byjolqG7eqCLa+Wfi7rah62VmLoqSXENaZnw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nix",
|
|
||||||
"rev": "a22328066416650471c3545b0b138669ea212ab4",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1709083642,
|
"lastModified": 1710889954,
|
||||||
"narHash": "sha256-7kkJQd4rZ+vFrzWu8sTRtta5D1kBG0LSRYAfhtmMlSo=",
|
"narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "b550fe4b4776908ac2a861124307045f8e717c8e",
|
"rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "release-23.11",
|
"ref": "nixpkgs-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"nixpkgs-cadical": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1722221733,
|
||||||
|
"narHash": "sha256-sga9SrrPb+pQJxG1ttJfMPheZvDOxApFfwXCFO0H9xw=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "12bf09802d77264e441f48e25459c10c93eada2e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "12bf09802d77264e441f48e25459c10c93eada2e",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs-old": {
|
"nixpkgs-old": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
@@ -120,44 +67,11 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-regression": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1643052045,
|
|
||||||
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1710889954,
|
|
||||||
"narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"lean4-mode": "lean4-mode",
|
"nixpkgs": "nixpkgs",
|
||||||
"nix": "nix",
|
"nixpkgs-cadical": "nixpkgs-cadical",
|
||||||
"nixpkgs": "nixpkgs_2",
|
|
||||||
"nixpkgs-old": "nixpkgs-old"
|
"nixpkgs-old": "nixpkgs-old"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
109
flake.nix
109
flake.nix
@@ -1,96 +1,61 @@
|
|||||||
{
|
{
|
||||||
description = "Lean interactive theorem prover";
|
description = "Lean development flake. Not intended for end users.";
|
||||||
|
|
||||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
# old nixpkgs used for portable release with older glibc (2.27)
|
# old nixpkgs used for portable release with older glibc (2.27)
|
||||||
inputs.nixpkgs-old.url = "github:NixOS/nixpkgs/nixos-19.03";
|
inputs.nixpkgs-old.url = "github:NixOS/nixpkgs/nixos-19.03";
|
||||||
inputs.nixpkgs-old.flake = false;
|
inputs.nixpkgs-old.flake = false;
|
||||||
|
# for cadical 1.9.5; sync with CMakeLists.txt
|
||||||
|
inputs.nixpkgs-cadical.url = "github:NixOS/nixpkgs/12bf09802d77264e441f48e25459c10c93eada2e";
|
||||||
inputs.flake-utils.url = "github:numtide/flake-utils";
|
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||||
inputs.nix.url = "github:NixOS/nix";
|
|
||||||
inputs.lean4-mode = {
|
|
||||||
url = "github:leanprover/lean4-mode";
|
|
||||||
flake = false;
|
|
||||||
};
|
|
||||||
# used *only* by `stage0-from-input` below
|
|
||||||
#inputs.lean-stage0 = {
|
|
||||||
# url = github:leanprover/lean4;
|
|
||||||
# inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
# inputs.flake-utils.follows = "flake-utils";
|
|
||||||
# inputs.nix.follows = "nix";
|
|
||||||
# inputs.lean4-mode.follows = "lean4-mode";
|
|
||||||
#};
|
|
||||||
|
|
||||||
outputs = { self, nixpkgs, nixpkgs-old, flake-utils, nix, lean4-mode, ... }@inputs: flake-utils.lib.eachDefaultSystem (system:
|
outputs = { self, nixpkgs, nixpkgs-old, flake-utils, ... }@inputs: flake-utils.lib.eachDefaultSystem (system:
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs { inherit system; };
|
||||||
inherit system;
|
|
||||||
# for `vscode-with-extensions`
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
# An old nixpkgs for creating releases with an old glibc
|
# An old nixpkgs for creating releases with an old glibc
|
||||||
pkgsDist-old = import nixpkgs-old { inherit system; };
|
pkgsDist-old = import nixpkgs-old { inherit system; };
|
||||||
# An old nixpkgs for creating releases with an old glibc
|
# An old nixpkgs for creating releases with an old glibc
|
||||||
pkgsDist-old-aarch = import nixpkgs-old { localSystem.config = "aarch64-unknown-linux-gnu"; };
|
pkgsDist-old-aarch = import nixpkgs-old { localSystem.config = "aarch64-unknown-linux-gnu"; };
|
||||||
|
pkgsCadical = import inputs.nixpkgs-cadical { inherit system; };
|
||||||
|
cadical = if pkgs.stdenv.isLinux then
|
||||||
|
# use statically-linked cadical on Linux to avoid glibc versioning troubles
|
||||||
|
pkgsCadical.pkgsStatic.cadical.overrideAttrs { doCheck = false; }
|
||||||
|
else pkgsCadical.cadical;
|
||||||
|
|
||||||
lean-packages = pkgs.callPackage (./nix/packages.nix) { src = ./.; inherit nix lean4-mode; };
|
lean-packages = pkgs.callPackage (./nix/packages.nix) { src = ./.; };
|
||||||
|
|
||||||
devShellWithDist = pkgsDist: pkgs.mkShell.override {
|
devShellWithDist = pkgsDist: pkgs.mkShell.override {
|
||||||
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
|
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
|
||||||
} ({
|
} ({
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
cmake gmp ccache
|
cmake gmp libuv ccache cadical
|
||||||
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
|
||||||
# TODO: only add when proven to not affect the flakification
|
gdb
|
||||||
#pkgs.python3
|
tree # for CI
|
||||||
];
|
];
|
||||||
# https://github.com/NixOS/nixpkgs/issues/60919
|
# https://github.com/NixOS/nixpkgs/issues/60919
|
||||||
hardeningDisable = [ "all" ];
|
hardeningDisable = [ "all" ];
|
||||||
# more convenient `ctest` output
|
# more convenient `ctest` output
|
||||||
CTEST_OUTPUT_ON_FAILURE = 1;
|
CTEST_OUTPUT_ON_FAILURE = 1;
|
||||||
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
|
||||||
GMP = pkgsDist.gmp.override { withStatic = true; };
|
GMP = pkgsDist.gmp.override { withStatic = true; };
|
||||||
GLIBC = pkgsDist.glibc;
|
LIBUV = pkgsDist.libuv.overrideAttrs (attrs: { configureFlags = ["--enable-static"]; });
|
||||||
GLIBC_DEV = pkgsDist.glibc.dev;
|
GLIBC = pkgsDist.glibc;
|
||||||
GCC_LIB = pkgsDist.gcc.cc.lib;
|
GLIBC_DEV = pkgsDist.glibc.dev;
|
||||||
ZLIB = pkgsDist.zlib;
|
GCC_LIB = pkgsDist.gcc.cc.lib;
|
||||||
GDB = pkgsDist.gdb;
|
ZLIB = pkgsDist.zlib;
|
||||||
});
|
GDB = pkgsDist.gdb;
|
||||||
|
});
|
||||||
in {
|
in {
|
||||||
packages = lean-packages // rec {
|
packages = {
|
||||||
debug = lean-packages.override { debug = true; };
|
# to be removed when Nix CI is not needed anymore
|
||||||
stage0debug = lean-packages.override { stage0debug = true; };
|
inherit (lean-packages) cacheRoots test update-stage0-commit ciShell;
|
||||||
asan = lean-packages.override { extraCMakeFlags = [ "-DLEAN_EXTRA_CXX_FLAGS=-fsanitize=address" "-DLEANC_EXTRA_FLAGS=-fsanitize=address" "-DSMALL_ALLOCATOR=OFF" "-DSYMBOLIC=OFF" ]; };
|
deprecated = lean-packages;
|
||||||
asandebug = asan.override { debug = true; };
|
|
||||||
tsan = lean-packages.override {
|
|
||||||
extraCMakeFlags = [ "-DLEAN_EXTRA_CXX_FLAGS=-fsanitize=thread" "-DLEANC_EXTRA_FLAGS=-fsanitize=thread" "-DCOMPRESSED_OBJECT_HEADER=OFF" ];
|
|
||||||
stage0 = (lean-packages.override {
|
|
||||||
# Compressed headers currently trigger data race reports in tsan.
|
|
||||||
# Turn them off for stage 0 as well so stage 1 can read its own stdlib.
|
|
||||||
extraCMakeFlags = [ "-DCOMPRESSED_OBJECT_HEADER=OFF" ];
|
|
||||||
}).stage1;
|
|
||||||
};
|
|
||||||
tsandebug = tsan.override { debug = true; };
|
|
||||||
stage0-from-input = lean-packages.override {
|
|
||||||
stage0 = pkgs.writeShellScriptBin "lean" ''
|
|
||||||
exec ${inputs.lean-stage0.packages.${system}.lean}/bin/lean -Dinterpreter.prefer_native=false "$@"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
inherit self;
|
|
||||||
};
|
};
|
||||||
defaultPackage = lean-packages.lean-all;
|
|
||||||
|
|
||||||
# The default development shell for working on lean itself
|
# The default development shell for working on lean itself
|
||||||
devShells.default = devShellWithDist pkgs;
|
devShells.default = devShellWithDist pkgs;
|
||||||
devShells.oldGlibc = devShellWithDist pkgsDist-old;
|
devShells.oldGlibc = devShellWithDist pkgsDist-old;
|
||||||
devShells.oldGlibcAArch = devShellWithDist pkgsDist-old-aarch;
|
devShells.oldGlibcAArch = devShellWithDist pkgsDist-old-aarch;
|
||||||
|
});
|
||||||
checks.lean = lean-packages.test;
|
|
||||||
}) // rec {
|
|
||||||
templates.pkg = {
|
|
||||||
path = ./nix/templates/pkg;
|
|
||||||
description = "A custom Lean package";
|
|
||||||
};
|
|
||||||
|
|
||||||
defaultTemplate = templates.pkg;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
|
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
|
||||||
stdenv, lib, cmake, gmp, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
|
stdenv, lib, cmake, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
|
||||||
... } @ args:
|
... } @ args:
|
||||||
with builtins;
|
with builtins;
|
||||||
rec {
|
lib.warn "The Nix-based build is deprecated" rec {
|
||||||
inherit stdenv;
|
inherit stdenv;
|
||||||
sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs);
|
sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs);
|
||||||
buildCMake = args: stdenv.mkDerivation ({
|
buildCMake = args: stdenv.mkDerivation ({
|
||||||
nativeBuildInputs = [ cmake ];
|
nativeBuildInputs = [ cmake ];
|
||||||
buildInputs = [ gmp llvmPackages.llvm ];
|
buildInputs = [ gmp libuv llvmPackages.llvm ];
|
||||||
# https://github.com/NixOS/nixpkgs/issues/60919
|
# https://github.com/NixOS/nixpkgs/issues/60919
|
||||||
hardeningDisable = [ "all" ];
|
hardeningDisable = [ "all" ];
|
||||||
dontStrip = (args.debug or debug);
|
dontStrip = (args.debug or debug);
|
||||||
@@ -17,7 +17,7 @@ rec {
|
|||||||
'';
|
'';
|
||||||
} // args // {
|
} // args // {
|
||||||
src = args.realSrc or (sourceByRegex args.src [ "[a-z].*" "CMakeLists\.txt" ]);
|
src = args.realSrc or (sourceByRegex args.src [ "[a-z].*" "CMakeLists\.txt" ]);
|
||||||
cmakeFlags = (args.cmakeFlags or [ "-DSTAGE=1" "-DPREV_STAGE=./faux-prev-stage" "-DUSE_GITHASH=OFF" ]) ++ (args.extraCMakeFlags or extraCMakeFlags) ++ lib.optional (args.debug or debug) [ "-DCMAKE_BUILD_TYPE=Debug" ];
|
cmakeFlags = (args.cmakeFlags or [ "-DSTAGE=1" "-DPREV_STAGE=./faux-prev-stage" "-DUSE_GITHASH=OFF" "-DCADICAL=${cadical}/bin/cadical" ]) ++ (args.extraCMakeFlags or extraCMakeFlags) ++ lib.optional (args.debug or debug) [ "-DCMAKE_BUILD_TYPE=Debug" ];
|
||||||
preConfigure = args.preConfigure or "" + ''
|
preConfigure = args.preConfigure or "" + ''
|
||||||
# ignore absence of submodule
|
# ignore absence of submodule
|
||||||
sed -i 's!lake/Lake.lean!!' CMakeLists.txt
|
sed -i 's!lake/Lake.lean!!' CMakeLists.txt
|
||||||
@@ -26,11 +26,7 @@ rec {
|
|||||||
lean-bin-tools-unwrapped = buildCMake {
|
lean-bin-tools-unwrapped = buildCMake {
|
||||||
name = "lean-bin-tools";
|
name = "lean-bin-tools";
|
||||||
outputs = [ "out" "leanc_src" ];
|
outputs = [ "out" "leanc_src" ];
|
||||||
realSrc = sourceByRegex (src + "/src") [ "CMakeLists\.txt" "cmake.*" "bin.*" "include.*" ".*\.in" "Leanc\.lean" ];
|
realSrc = sourceByRegex (src + "/src") [ "CMakeLists\.txt" "[a-z].*" ".*\.in" "Leanc\.lean" ];
|
||||||
preConfigure = ''
|
|
||||||
touch empty.cpp
|
|
||||||
sed -i 's/add_subdirectory.*//;s/set(LEAN_OBJS.*/set(LEAN_OBJS empty.cpp)/' CMakeLists.txt
|
|
||||||
'';
|
|
||||||
dontBuild = true;
|
dontBuild = true;
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir $out $leanc_src
|
mkdir $out $leanc_src
|
||||||
@@ -45,11 +41,10 @@ rec {
|
|||||||
leancpp = buildCMake {
|
leancpp = buildCMake {
|
||||||
name = "leancpp";
|
name = "leancpp";
|
||||||
src = src + "/src";
|
src = src + "/src";
|
||||||
buildFlags = [ "leancpp" "leanrt" "leanrt_initial-exec" "shell" ];
|
buildFlags = [ "leancpp" "leanrt" "leanrt_initial-exec" "leanshell" "leanmain" ];
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
mv lib/ $out/
|
mv lib/ $out/
|
||||||
mv shell/CMakeFiles/shell.dir/lean.cpp.o $out/lib
|
|
||||||
mv runtime/libleanrt_initial-exec.a $out/lib
|
mv runtime/libleanrt_initial-exec.a $out/lib
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
@@ -87,7 +82,8 @@ rec {
|
|||||||
leanFlags = [ "-DwarningAsError=true" ];
|
leanFlags = [ "-DwarningAsError=true" ];
|
||||||
} // args);
|
} // args);
|
||||||
Init' = build { name = "Init"; deps = []; };
|
Init' = build { name = "Init"; deps = []; };
|
||||||
Lean' = build { name = "Lean"; deps = [ Init' ]; };
|
Std' = build { name = "Std"; deps = [ Init' ]; };
|
||||||
|
Lean' = build { name = "Lean"; deps = [ Std' ]; };
|
||||||
attachSharedLib = sharedLib: pkg: pkg // {
|
attachSharedLib = sharedLib: pkg: pkg // {
|
||||||
inherit sharedLib;
|
inherit sharedLib;
|
||||||
mods = mapAttrs (_: m: m // { inherit sharedLib; propagatedLoadDynlibs = []; }) pkg.mods;
|
mods = mapAttrs (_: m: m // { inherit sharedLib; propagatedLoadDynlibs = []; }) pkg.mods;
|
||||||
@@ -95,7 +91,8 @@ rec {
|
|||||||
in (all: all // all.lean) rec {
|
in (all: all // all.lean) rec {
|
||||||
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
|
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
|
||||||
Init = attachSharedLib leanshared Init';
|
Init = attachSharedLib leanshared Init';
|
||||||
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Init ]; };
|
Std = attachSharedLib leanshared Std' // { allExternalDeps = [ Init ]; };
|
||||||
|
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Std ]; };
|
||||||
Lake = build {
|
Lake = build {
|
||||||
name = "Lake";
|
name = "Lake";
|
||||||
src = src + "/src/lake";
|
src = src + "/src/lake";
|
||||||
@@ -109,41 +106,45 @@ rec {
|
|||||||
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
|
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
|
||||||
src = src + "/src/lake";
|
src = src + "/src/lake";
|
||||||
};
|
};
|
||||||
stdlib = [ Init Lean Lake ];
|
stdlib = [ Init Std Lean Lake ];
|
||||||
modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); };
|
modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); };
|
||||||
depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; };
|
depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; };
|
||||||
iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; };
|
iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; };
|
||||||
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
|
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
|
||||||
stdlibLinkFlags = "-L${Init.staticLib} -L${Lean.staticLib} -L${Lake.staticLib} -L${leancpp}/lib/lean";
|
stdlibLinkFlags = "${lib.concatMapStringsSep " " (l: "-L${l.staticLib}") stdlib} -L${leancpp}/lib/lean";
|
||||||
libInit_shared = runCommand "libInit_shared" { buildInputs = [ stdenv.cc ]; libName = "libInit_shared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
libInit_shared = runCommand "libInit_shared" { buildInputs = [ stdenv.cc ]; libName = "libInit_shared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared -Wl,-Bsymbolic \
|
touch empty.c
|
||||||
-Wl,--whole-archive -lInit ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++ -lm ${stdlibLinkFlags} \
|
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
|
||||||
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
|
'';
|
||||||
-o $out/$libName
|
leanshared_1 = runCommand "leanshared_1" { buildInputs = [ stdenv.cc ]; libName = "leanshared_1${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||||
|
mkdir $out
|
||||||
|
touch empty.c
|
||||||
|
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
|
||||||
'';
|
'';
|
||||||
leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared -Wl,-Bsymbolic \
|
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Wl,-Bsymbolic"} \
|
||||||
${libInit_shared}/* -Wl,--whole-archive -lLean -lleancpp -Wl,--no-whole-archive -lstdc++ -lm ${stdlibLinkFlags} \
|
-Wl,--whole-archive ${leancpp}/lib/temp/libleanshell.a -lInit -lStd -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++ \
|
||||||
|
-lm ${stdlibLinkFlags} \
|
||||||
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
|
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
|
||||||
-o $out/$libName
|
-o $out/$libName
|
||||||
'';
|
'';
|
||||||
mods = foldl' (mods: pkg: mods // pkg.mods) {} stdlib;
|
mods = foldl' (mods: pkg: mods // pkg.mods) {} stdlib;
|
||||||
print-paths = Lean.makePrintPathsFor [] mods;
|
print-paths = Lean.makePrintPathsFor [] mods;
|
||||||
leanc = writeShellScriptBin "leanc" ''
|
leanc = writeShellScriptBin "leanc" ''
|
||||||
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${libInit_shared} -L${leanshared} "$@"
|
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${libInit_shared} -L${leanshared_1} -L${leanshared} "$@"
|
||||||
'';
|
'';
|
||||||
lean = runCommand "lean" { buildInputs = lib.optional stdenv.isDarwin darwin.cctools; } ''
|
lean = runCommand "lean" { buildInputs = lib.optional stdenv.isDarwin darwin.cctools; } ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
${leanc}/bin/leanc ${leancpp}/lib/lean.cpp.o ${libInit_shared}/* ${leanshared}/* -o $out/bin/lean
|
${leanc}/bin/leanc ${leancpp}/lib/temp/libleanmain.a ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* -o $out/bin/lean
|
||||||
'';
|
'';
|
||||||
# derivation following the directory layout of the "basic" setup, mostly useful for running tests
|
# derivation following the directory layout of the "basic" setup, mostly useful for running tests
|
||||||
lean-all = stdenv.mkDerivation {
|
lean-all = stdenv.mkDerivation {
|
||||||
name = "lean-${desc}";
|
name = "lean-${desc}";
|
||||||
buildCommand = ''
|
buildCommand = ''
|
||||||
mkdir -p $out/bin $out/lib/lean
|
mkdir -p $out/bin $out/lib/lean
|
||||||
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${libInit_shared}/* ${leanshared}/* $out/lib/lean/
|
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* $out/lib/lean/
|
||||||
# put everything in a single final derivation so `IO.appDir` references work
|
# put everything in a single final derivation so `IO.appDir` references work
|
||||||
cp ${lean}/bin/lean ${leanc}/bin/leanc ${Lake-Main.executable}/bin/lake $out/bin
|
cp ${lean}/bin/lean ${leanc}/bin/leanc ${Lake-Main.executable}/bin/lake $out/bin
|
||||||
# NOTE: `lndir` will not override existing `bin/leanc`
|
# NOTE: `lndir` will not override existing `bin/leanc`
|
||||||
@@ -151,15 +152,13 @@ rec {
|
|||||||
'';
|
'';
|
||||||
meta.mainProgram = "lean";
|
meta.mainProgram = "lean";
|
||||||
};
|
};
|
||||||
cacheRoots = linkFarmFromDrvs "cacheRoots" [
|
cacheRoots = linkFarmFromDrvs "cacheRoots" ([
|
||||||
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
|
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
|
||||||
# .o files are not a runtime dependency on macOS because of lack of thin archives
|
] ++ map (lib: lib.oTree) stdlib);
|
||||||
Lean.oTree Lake.oTree
|
|
||||||
];
|
|
||||||
test = buildCMake {
|
test = buildCMake {
|
||||||
name = "lean-test-${desc}";
|
name = "lean-test-${desc}";
|
||||||
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
|
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
|
||||||
buildInputs = [ gmp perl git ];
|
buildInputs = [ gmp libuv perl git cadical ];
|
||||||
preConfigure = ''
|
preConfigure = ''
|
||||||
cd src
|
cd src
|
||||||
'';
|
'';
|
||||||
@@ -170,7 +169,7 @@ rec {
|
|||||||
ln -sf ${lean-all}/* .
|
ln -sf ${lean-all}/* .
|
||||||
'';
|
'';
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
|
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi' -j$NIX_BUILD_CORES
|
||||||
'';
|
'';
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir $out
|
mkdir $out
|
||||||
@@ -178,7 +177,7 @@ rec {
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
update-stage0 =
|
update-stage0 =
|
||||||
let cTree = symlinkJoin { name = "cs"; paths = [ Init.cTree Lean.cTree ]; }; in
|
let cTree = symlinkJoin { name = "cs"; paths = map (lib: lib.cTree) stdlib; }; in
|
||||||
writeShellScriptBin "update-stage0" ''
|
writeShellScriptBin "update-stage0" ''
|
||||||
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/lib/update-stage0"}
|
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/lib/update-stage0"}
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
{ lean, lean-leanDeps ? lean, lean-final ? lean, leanc,
|
{ lean, lean-leanDeps ? lean, lean-final ? lean, leanc,
|
||||||
stdenv, lib, coreutils, gnused, writeShellScriptBin, bash, lean-emacs, lean-vscode, nix, substituteAll, symlinkJoin, linkFarmFromDrvs,
|
stdenv, lib, coreutils, gnused, writeShellScriptBin, bash, substituteAll, symlinkJoin, linkFarmFromDrvs,
|
||||||
runCommand, darwin, mkShell, ... }:
|
runCommand, darwin, mkShell, ... }:
|
||||||
let lean-final' = lean-final; in
|
let lean-final' = lean-final; in
|
||||||
lib.makeOverridable (
|
lib.makeOverridable (
|
||||||
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
|
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
|
||||||
# Lean dependencies. Each entry should be an output of buildLeanPackage.
|
# Lean dependencies. Each entry should be an output of buildLeanPackage.
|
||||||
deps ? [ lean.Lean ],
|
deps ? [ lean.Init lean.Std lean.Lean ],
|
||||||
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
|
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
|
||||||
staticLibDeps ? [],
|
staticLibDeps ? [],
|
||||||
# Whether to wrap static library inputs in a -Wl,--start-group [...] -Wl,--end-group to ensure dependencies are resolved.
|
# Whether to wrap static library inputs in a -Wl,--start-group [...] -Wl,--end-group to ensure dependencies are resolved.
|
||||||
@@ -197,19 +197,6 @@ with builtins; let
|
|||||||
then map (m: m.module) header.imports
|
then map (m: m.module) header.imports
|
||||||
else abort "errors while parsing imports of ${mod}:\n${lib.concatStringsSep "\n" header.errors}";
|
else abort "errors while parsing imports of ${mod}:\n${lib.concatStringsSep "\n" header.errors}";
|
||||||
in mkMod mod (map (dep: if modDepsMap ? ${dep} then modCandidates.${dep} else externalModMap.${dep}) deps)) modDepsMap;
|
in mkMod mod (map (dep: if modDepsMap ? ${dep} then modCandidates.${dep} else externalModMap.${dep}) deps)) modDepsMap;
|
||||||
makeEmacsWrapper = name: emacs: lean: writeShellScriptBin name ''
|
|
||||||
${emacs} --eval "(progn (setq lean4-rootdir \"${lean}\"))" "$@"
|
|
||||||
'';
|
|
||||||
makeVSCodeWrapper = name: lean: writeShellScriptBin name ''
|
|
||||||
PATH=${lean}/bin:$PATH ${lean-vscode}/bin/code "$@"
|
|
||||||
'';
|
|
||||||
printPaths = deps: writeShellScriptBin "print-paths" ''
|
|
||||||
echo '${toJSON {
|
|
||||||
oleanPath = [(depRoot "print-paths" deps)];
|
|
||||||
srcPath = ["."] ++ map (dep: dep.src) allExternalDeps;
|
|
||||||
loadDynlibPaths = map pathOfSharedLib (loadDynlibsOfDeps deps);
|
|
||||||
}}'
|
|
||||||
'';
|
|
||||||
expandGlob = g:
|
expandGlob = g:
|
||||||
if typeOf g == "string" then [g]
|
if typeOf g == "string" then [g]
|
||||||
else if g.glob == "one" then [g.mod]
|
else if g.glob == "one" then [g.mod]
|
||||||
@@ -224,7 +211,8 @@ with builtins; let
|
|||||||
allLinkFlags = lib.foldr (shared: acc: acc ++ [ "-L${shared}" "-l${shared.linkName or shared.name}" ]) linkFlags allNativeSharedLibs;
|
allLinkFlags = lib.foldr (shared: acc: acc ++ [ "-L${shared}" "-l${shared.linkName or shared.name}" ]) linkFlags allNativeSharedLibs;
|
||||||
|
|
||||||
objects = mapAttrs (_: m: m.obj) mods';
|
objects = mapAttrs (_: m: m.obj) mods';
|
||||||
staticLib = runCommand "${name}-lib" { buildInputs = [ stdenv.cc.bintools.bintools ]; } ''
|
bintools = if stdenv.isDarwin then darwin.cctools else stdenv.cc.bintools.bintools;
|
||||||
|
staticLib = runCommand "${name}-lib" { buildInputs = [ bintools ]; } ''
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
ar Trcs $out/lib${libName}.a ${lib.concatStringsSep " " (map (drv: "${drv}/${drv.oPath}") (attrValues objects))};
|
ar Trcs $out/lib${libName}.a ${lib.concatStringsSep " " (map (drv: "${drv}/${drv.oPath}") (attrValues objects))};
|
||||||
'';
|
'';
|
||||||
@@ -249,55 +237,11 @@ in rec {
|
|||||||
${if stdenv.isDarwin then "-Wl,-force_load,${staticLib}/lib${libName}.a" else "-Wl,--whole-archive ${staticLib}/lib${libName}.a -Wl,--no-whole-archive"} \
|
${if stdenv.isDarwin then "-Wl,-force_load,${staticLib}/lib${libName}.a" else "-Wl,--whole-archive ${staticLib}/lib${libName}.a -Wl,--no-whole-archive"} \
|
||||||
${lib.concatStringsSep " " (map (d: "${d.sharedLib}/*") deps)}'';
|
${lib.concatStringsSep " " (map (d: "${d.sharedLib}/*") deps)}'';
|
||||||
executable = lib.makeOverridable ({ withSharedStdlib ? true }: let
|
executable = lib.makeOverridable ({ withSharedStdlib ? true }: let
|
||||||
objPaths = map (drv: "${drv}/${drv.oPath}") (attrValues objects) ++ lib.optional withSharedStdlib "${lean-final.libInit_shared}/* ${lean-final.leanshared}/*";
|
objPaths = map (drv: "${drv}/${drv.oPath}") (attrValues objects) ++ lib.optional withSharedStdlib "${lean-final.leanshared}/*";
|
||||||
in runCommand executableName { buildInputs = [ stdenv.cc leanc ]; } ''
|
in runCommand executableName { buildInputs = [ stdenv.cc leanc ]; } ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
leanc ${staticLibLinkWrapper (lib.concatStringsSep " " (objPaths ++ map (d: "${d}/*.a") allStaticLibDeps))} \
|
leanc ${staticLibLinkWrapper (lib.concatStringsSep " " (objPaths ++ map (d: "${d}/*.a") allStaticLibDeps))} \
|
||||||
-o $out/bin/${executableName} \
|
-o $out/bin/${executableName} \
|
||||||
${lib.concatStringsSep " " allLinkFlags}
|
${lib.concatStringsSep " " allLinkFlags}
|
||||||
'') {};
|
'') {};
|
||||||
|
|
||||||
lean-package = writeShellScriptBin "lean" ''
|
|
||||||
LEAN_PATH=${modRoot}:$LEAN_PATH LEAN_SRC_PATH=$LEAN_SRC_PATH:${src} exec ${lean-final}/bin/lean "$@"
|
|
||||||
'';
|
|
||||||
emacs-package = makeEmacsWrapper "emacs-package" lean-package;
|
|
||||||
vscode-package = makeVSCodeWrapper "vscode-package" lean-package;
|
|
||||||
|
|
||||||
link-ilean = writeShellScriptBin "link-ilean" ''
|
|
||||||
dest=''${1:-.}
|
|
||||||
mkdir -p $dest/build/lib
|
|
||||||
ln -sf ${iTree}/* $dest/build/lib
|
|
||||||
'';
|
|
||||||
|
|
||||||
makePrintPathsFor = deps: mods: printPaths deps // mapAttrs (_: mod: makePrintPathsFor (deps ++ [mod]) mods) mods;
|
|
||||||
print-paths = makePrintPathsFor [] (mods' // externalModMap);
|
|
||||||
# `lean` wrapper that dynamically runs Nix for the actual `lean` executable so the same editor can be
|
|
||||||
# used for multiple projects/after upgrading the `lean` input/for editing both stage 1 and the tests
|
|
||||||
lean-bin-dev = substituteAll {
|
|
||||||
name = "lean";
|
|
||||||
dir = "bin";
|
|
||||||
src = ./lean-dev.in;
|
|
||||||
isExecutable = true;
|
|
||||||
srcRoot = fullSrc; # use root flake.nix in case of Lean repo
|
|
||||||
inherit bash nix srcTarget srcArgs;
|
|
||||||
};
|
|
||||||
lake-dev = substituteAll {
|
|
||||||
name = "lake";
|
|
||||||
dir = "bin";
|
|
||||||
src = ./lake-dev.in;
|
|
||||||
isExecutable = true;
|
|
||||||
srcRoot = fullSrc; # use root flake.nix in case of Lean repo
|
|
||||||
inherit bash nix srcTarget srcArgs;
|
|
||||||
};
|
|
||||||
lean-dev = symlinkJoin { name = "lean-dev"; paths = [ lean-bin-dev lake-dev ]; };
|
|
||||||
emacs-dev = makeEmacsWrapper "emacs-dev" "${lean-emacs}/bin/emacs" lean-dev;
|
|
||||||
emacs-path-dev = makeEmacsWrapper "emacs-path-dev" "emacs" lean-dev;
|
|
||||||
vscode-dev = makeVSCodeWrapper "vscode-dev" lean-dev;
|
|
||||||
|
|
||||||
devShell = mkShell {
|
|
||||||
buildInputs = [ nix ];
|
|
||||||
shellHook = ''
|
|
||||||
export LEAN_SRC_PATH="${srcPath}"
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
{ src, pkgs, nix, ... } @ args:
|
{ src, pkgs, ... } @ args:
|
||||||
with pkgs;
|
with pkgs;
|
||||||
let
|
let
|
||||||
nix-pinned = writeShellScriptBin "nix" ''
|
|
||||||
${nix.packages.${system}.default}/bin/nix --experimental-features 'nix-command flakes' --extra-substituters https://lean4.cachix.org/ --option warn-dirty false "$@"
|
|
||||||
'';
|
|
||||||
# https://github.com/NixOS/nixpkgs/issues/130963
|
# https://github.com/NixOS/nixpkgs/issues/130963
|
||||||
llvmPackages = if stdenv.isDarwin then llvmPackages_11 else llvmPackages_15;
|
llvmPackages = if stdenv.isDarwin then llvmPackages_11 else llvmPackages_15;
|
||||||
cc = (ccacheWrapper.override rec {
|
cc = (ccacheWrapper.override rec {
|
||||||
@@ -42,40 +39,9 @@ let
|
|||||||
inherit (lean) stdenv;
|
inherit (lean) stdenv;
|
||||||
lean = lean.stage1;
|
lean = lean.stage1;
|
||||||
inherit (lean.stage1) leanc;
|
inherit (lean.stage1) leanc;
|
||||||
inherit lean-emacs lean-vscode;
|
|
||||||
nix = nix-pinned;
|
|
||||||
}));
|
}));
|
||||||
lean4-mode = emacsPackages.melpaBuild {
|
|
||||||
pname = "lean4-mode";
|
|
||||||
version = "1";
|
|
||||||
commit = "1";
|
|
||||||
src = args.lean4-mode;
|
|
||||||
packageRequires = with pkgs.emacsPackages.melpaPackages; [ dash f flycheck magit-section lsp-mode s ];
|
|
||||||
recipe = pkgs.writeText "recipe" ''
|
|
||||||
(lean4-mode
|
|
||||||
:repo "leanprover/lean4-mode"
|
|
||||||
:fetcher github
|
|
||||||
:files ("*.el" "data"))
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
lean-emacs = emacsWithPackages [ lean4-mode ];
|
|
||||||
# updating might be nicer by building from source from a flake input, but this is good enough for now
|
|
||||||
vscode-lean4 = vscode-utils.extensionFromVscodeMarketplace {
|
|
||||||
name = "lean4";
|
|
||||||
publisher = "leanprover";
|
|
||||||
version = "0.0.63";
|
|
||||||
sha256 = "sha256-kjEex7L0F2P4pMdXi4NIZ1y59ywJVubqDqsoYagZNkI=";
|
|
||||||
};
|
|
||||||
lean-vscode = vscode-with-extensions.override {
|
|
||||||
vscodeExtensions = [ vscode-lean4 ];
|
|
||||||
};
|
|
||||||
in {
|
in {
|
||||||
inherit cc lean4-mode buildLeanPackage llvmPackages vscode-lean4;
|
inherit cc buildLeanPackage llvmPackages;
|
||||||
lean = lean.stage1;
|
|
||||||
stage0print-paths = lean.stage1.Lean.print-paths;
|
|
||||||
HEAD-as-stage0 = (lean.stage1.Lean.overrideArgs { srcTarget = "..#stage0-from-input.stage0"; srcArgs = "(--override-input lean-stage0 ..\?rev=$(git rev-parse HEAD) -- -Dinterpreter.prefer_native=false \"$@\")"; });
|
|
||||||
HEAD-as-stage1 = (lean.stage1.Lean.overrideArgs { srcTarget = "..\?rev=$(git rev-parse HEAD)#stage0"; });
|
|
||||||
nix = nix-pinned;
|
|
||||||
nixpkgs = pkgs;
|
nixpkgs = pkgs;
|
||||||
ciShell = writeShellScriptBin "ciShell" ''
|
ciShell = writeShellScriptBin "ciShell" ''
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
@@ -83,5 +49,4 @@ in {
|
|||||||
# prefix lines with cumulative and individual execution time
|
# prefix lines with cumulative and individual execution time
|
||||||
"$@" |& ts -i "(%.S)]" | ts -s "[%M:%S"
|
"$@" |& ts -i "(%.S)]" | ts -s "[%M:%S"
|
||||||
'';
|
'';
|
||||||
vscode = lean-vscode;
|
} // lean.stage1
|
||||||
} // lean.stage1.Lean // lean.stage1 // lean
|
|
||||||
|
|||||||
22
releases_drafts/README.md
Normal file
22
releases_drafts/README.md
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
Draft release notes
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
This folder contains drafts of release notes for inclusion in `RELEASES.md`.
|
||||||
|
During the process to create a release candidate, we look through all the commits that make up the release
|
||||||
|
to prepare the release notes, and in that process we take these drafts into account.
|
||||||
|
|
||||||
|
Guidelines:
|
||||||
|
- You should prefer adding release notes to commit messages over adding anything to this folder.
|
||||||
|
A release note should briefly explain the impact of a change from a user's point of view.
|
||||||
|
Please mark these parts out with words such as **release notes** and/or **breaking changes**.
|
||||||
|
- It is not necessary to add anything to this folder. It is meant for larger features that span multiple PRs,
|
||||||
|
or for anything that would be helpful when preparing the release notes that might be missed
|
||||||
|
by someone reading through the change log.
|
||||||
|
- If the PR that adds a feature simultaneously adds a draft release note, including the PR number is not required
|
||||||
|
since it can be obtained from the git history for the file.
|
||||||
|
|
||||||
|
When release notes are prepared, all the draft release notes are deleted from this folder.
|
||||||
|
For release candidates beyond the first one, you can either update `RELEASE.md` directly
|
||||||
|
or continue to add drafts.
|
||||||
|
|
||||||
|
When a release is finalized, we will copy the completed release notes from `RELEASE.md` to the `master` branch.
|
||||||
3
releases_drafts/hashmap.md
Normal file
3
releases_drafts/hashmap.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
* The `Lean` module has switched from `Lean.HashMap` and `Lean.HashSet` to `Std.HashMap` and `Std.HashSet`. `Lean.HashMap` and `Lean.HashSet` are now deprecated and will be removed in a future release. Users of `Lean` APIs that interact with hash maps, for example `Lean.Environment.const2ModIdx`, might encounter minor breakage due to the following breaking changes from `Lean.HashMap` to `Std.HashMap`:
|
||||||
|
* query functions use the term `get` instead of `find`,
|
||||||
|
* the notation `map[key]` no longer returns an optional value but expects a proof that the key is present in the map instead. The previous behavior is available via the `map[key]?` notation.
|
||||||
1
releases_drafts/libuv.md
Normal file
1
releases_drafts/libuv.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* #4963 [LibUV](https://libuv.org/) is now required to build Lean. This change only affects developers who compile Lean themselves instead of obtaining toolchains via `elan`. We have updated the official build instructions with information on how to obtain LibUV on our supported platforms.
|
||||||
17
releases_drafts/new-variable.md
Normal file
17
releases_drafts/new-variable.md
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
**breaking change**
|
||||||
|
|
||||||
|
The effect of the `variable` command on proofs of `theorem`s has been changed. Whether such section variables are accessible in the proof now depends only on the theorem signature and other top-level commands, not on the proof itself.
|
||||||
|
This change ensures that
|
||||||
|
* the statement of a theorem is independent of its proof. In other words, changes in the proof cannot change the theorem statement.
|
||||||
|
* tactics such as `induction` cannot accidentally include a section variable.
|
||||||
|
* the proof can be elaborated in parallel to subsequent declarations in a future version of Lean.
|
||||||
|
|
||||||
|
The effect of `variable`s on the theorem header as well as on other kinds of declarations is unchanged.
|
||||||
|
|
||||||
|
Specifically, section variables are included if they
|
||||||
|
* are directly referenced by the theorem header,
|
||||||
|
* are included via the new `include` command in the current section and not subsequently mentioned in an `omit` statement,
|
||||||
|
* are directly referenced by any variable included by these rules, OR
|
||||||
|
* are instance-implicit variables that reference only variables included by these rules.
|
||||||
|
|
||||||
|
For porting, a new option `deprecated.oldSectionVars` is included to locally switch back to the old behavior.
|
||||||
@@ -15,4 +15,19 @@ for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
|
|||||||
cp $f stage0/$f
|
cp $f stage0/$f
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# special handling for Lake files due to its nested directory
|
||||||
|
# copy the README to ensure the `stage0/src/lake` directory is comitted
|
||||||
|
for f in $(git ls-files 'src/lake/Lake/*' src/lake/Lake.lean src/lake/README.md ':!:src/lakefile.toml'); do
|
||||||
|
if [[ $f == *.lean ]]; then
|
||||||
|
f=${f#src/lake}
|
||||||
|
f=${f%.lean}.c
|
||||||
|
mkdir -p $(dirname stage0/stdlib/$f)
|
||||||
|
cp ${CP_C_PARAMS:-} $CSRCS/$f stage0/stdlib/$f
|
||||||
|
else
|
||||||
|
mkdir -p $(dirname stage0/$f)
|
||||||
|
cp $f stage0/$f
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
git add stage0
|
git add stage0
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ $CP $GLIBC/lib/*crt* llvm/lib/
|
|||||||
$CP $GLIBC/lib/*crt* stage1/lib/
|
$CP $GLIBC/lib/*crt* stage1/lib/
|
||||||
# runtime
|
# runtime
|
||||||
(cd llvm; $CP --parents lib/clang/*/lib/*/{clang_rt.*.o,libclang_rt.builtins*} ../stage1)
|
(cd llvm; $CP --parents lib/clang/*/lib/*/{clang_rt.*.o,libclang_rt.builtins*} ../stage1)
|
||||||
$CP llvm/lib/*/lib{c++,c++abi,unwind}.* $GMP/lib/libgmp.a stage1/lib/
|
$CP llvm/lib/*/lib{c++,c++abi,unwind}.* $GMP/lib/libgmp.a $LIBUV/lib/libuv.a stage1/lib/
|
||||||
# LLVM 15 appears to ship the dependencies in 'llvm/lib/<target-triple>/' and 'llvm/include/<target-triple>/'
|
# LLVM 15 appears to ship the dependencies in 'llvm/lib/<target-triple>/' and 'llvm/include/<target-triple>/'
|
||||||
# but clang-15 that we use to compile is linked against 'llvm/lib/' and 'llvm/include'
|
# but clang-15 that we use to compile is linked against 'llvm/lib/' and 'llvm/include'
|
||||||
# https://github.com/llvm/llvm-project/issues/54955
|
# https://github.com/llvm/llvm-project/issues/54955
|
||||||
@@ -62,8 +62,8 @@ fi
|
|||||||
# use `-nostdinc` to make sure headers are not visible by default (in particular, not to `#include_next` in the clang headers),
|
# use `-nostdinc` to make sure headers are not visible by default (in particular, not to `#include_next` in the clang headers),
|
||||||
# but do not change sysroot so users can still link against system libs
|
# but do not change sysroot so users can still link against system libs
|
||||||
echo -n " -DLEANC_INTERNAL_FLAGS='-nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
|
echo -n " -DLEANC_INTERNAL_FLAGS='-nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
|
||||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
|
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
|
||||||
# when not using the above flags, link GMP dynamically/as usual
|
# when not using the above flags, link GMP dynamically/as usual
|
||||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-Wl,--as-needed -lgmp -Wl,--no-as-needed'"
|
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-Wl,--as-needed -lgmp -luv -Wl,--no-as-needed'"
|
||||||
# do not set `LEAN_CC` for tests
|
# do not set `LEAN_CC` for tests
|
||||||
echo -n " -DLEAN_TEST_VARS=''"
|
echo -n " -DLEAN_TEST_VARS=''"
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ set -uxo pipefail
|
|||||||
# use full LLVM release for compiling C++ code, but subset for compiling C code and distribution
|
# use full LLVM release for compiling C++ code, but subset for compiling C code and distribution
|
||||||
|
|
||||||
GMP=${GMP:-$(brew --prefix)}
|
GMP=${GMP:-$(brew --prefix)}
|
||||||
|
LIBUV=${LIBUV:-$(brew --prefix)}
|
||||||
|
|
||||||
[[ -d llvm ]] || (mkdir llvm; gtar xf $1 --strip-components 1 --directory llvm)
|
[[ -d llvm ]] || (mkdir llvm; gtar xf $1 --strip-components 1 --directory llvm)
|
||||||
[[ -d llvm-host ]] || if [[ "$#" -gt 1 ]]; then
|
[[ -d llvm-host ]] || if [[ "$#" -gt 1 ]]; then
|
||||||
@@ -46,8 +47,9 @@ echo -n " -DLEAN_EXTRA_CXX_FLAGS='${EXTRA_FLAGS:-}'"
|
|||||||
if [[ -L llvm-host ]]; then
|
if [[ -L llvm-host ]]; then
|
||||||
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang"
|
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang"
|
||||||
gcp $GMP/lib/libgmp.a stage1/lib/
|
gcp $GMP/lib/libgmp.a stage1/lib/
|
||||||
|
gcp $LIBUV/lib/libuv.a stage1/lib/
|
||||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/libc -fuse-ld=lld'"
|
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/libc -fuse-ld=lld'"
|
||||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp'"
|
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp -luv'"
|
||||||
else
|
else
|
||||||
echo -n " -DCMAKE_C_COMPILER=$PWD/llvm-host/bin/clang -DLEANC_OPTS='--sysroot $PWD/stage1 -resource-dir $PWD/stage1/lib/clang/15.0.1 ${EXTRA_FLAGS:-}'"
|
echo -n " -DCMAKE_C_COMPILER=$PWD/llvm-host/bin/clang -DLEANC_OPTS='--sysroot $PWD/stage1 -resource-dir $PWD/stage1/lib/clang/15.0.1 ${EXTRA_FLAGS:-}'"
|
||||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/libc -fuse-ld=lld'"
|
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/libc -fuse-ld=lld'"
|
||||||
|
|||||||
@@ -31,15 +31,15 @@ cp /clang64/lib/{crtbegin,crtend,crt2,dllcrt2}.o stage1/lib/
|
|||||||
# runtime
|
# runtime
|
||||||
(cd llvm; cp --parents lib/clang/*/lib/*/libclang_rt.builtins* ../stage1)
|
(cd llvm; cp --parents lib/clang/*/lib/*/libclang_rt.builtins* ../stage1)
|
||||||
# further dependencies
|
# further dependencies
|
||||||
cp /clang64/lib/lib{m,bcrypt,mingw32,moldname,mingwex,msvcrt,pthread,advapi32,shell32,user32,kernel32,ucrtbase}.* /clang64/lib/libgmp.a llvm/lib/lib{c++,c++abi,unwind}.a stage1/lib/
|
cp /clang64/lib/lib{m,bcrypt,mingw32,moldname,mingwex,msvcrt,pthread,advapi32,shell32,user32,kernel32,ucrtbase}.* /clang64/lib/libgmp.a /clang64/lib/libuv.a llvm/lib/lib{c++,c++abi,unwind}.a stage1/lib/
|
||||||
echo -n " -DLEAN_STANDALONE=ON"
|
echo -n " -DLEAN_STANDALONE=ON"
|
||||||
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang.exe -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER=$PWD/llvm/bin/clang++.exe -DCMAKE_CXX_COMPILER_WORKS=1 -DLEAN_CXX_STDLIB='-lc++ -lc++abi'"
|
echo -n " -DCMAKE_C_COMPILER=$PWD/stage1/bin/clang.exe -DCMAKE_C_COMPILER_WORKS=1 -DCMAKE_CXX_COMPILER=$PWD/llvm/bin/clang++.exe -DCMAKE_CXX_COMPILER_WORKS=1 -DLEAN_CXX_STDLIB='-lc++ -lc++abi'"
|
||||||
echo -n " -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_CXX_COMPILER=clang++"
|
echo -n " -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_CXX_COMPILER=clang++"
|
||||||
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter /clang64/include/'"
|
echo -n " -DLEAN_EXTRA_CXX_FLAGS='--sysroot $PWD/llvm -idirafter /clang64/include/'"
|
||||||
echo -n " -DLEANC_INTERNAL_FLAGS='--sysroot ROOT -nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang.exe"
|
echo -n " -DLEANC_INTERNAL_FLAGS='--sysroot ROOT -nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang.exe"
|
||||||
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -static-libgcc -Wl,-Bstatic -lgmp -lunwind -Wl,-Bdynamic -fuse-ld=lld'"
|
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -static-libgcc -Wl,-Bstatic -lgmp -luv -lunwind -Wl,-Bdynamic -fuse-ld=lld'"
|
||||||
# when not using the above flags, link GMP dynamically/as usual
|
# when not using the above flags, link GMP dynamically/as usual
|
||||||
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp -lucrtbase'"
|
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-lgmp -luv -lucrtbase'"
|
||||||
# do not set `LEAN_CC` for tests
|
# do not set `LEAN_CC` for tests
|
||||||
echo -n " -DAUTO_THREAD_FINALIZATION=OFF -DSTAGE0_AUTO_THREAD_FINALIZATION=OFF"
|
echo -n " -DAUTO_THREAD_FINALIZATION=OFF -DSTAGE0_AUTO_THREAD_FINALIZATION=OFF"
|
||||||
echo -n " -DLEAN_TEST_VARS=''"
|
echo -n " -DLEAN_TEST_VARS=''"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.10)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
cmake_policy(SET CMP0054 NEW)
|
cmake_policy(SET CMP0054 NEW)
|
||||||
|
cmake_policy(SET CMP0110 NEW)
|
||||||
if(NOT (${CMAKE_GENERATOR} MATCHES "Unix Makefiles"))
|
if(NOT (${CMAKE_GENERATOR} MATCHES "Unix Makefiles"))
|
||||||
message(FATAL_ERROR "The only supported CMake generator at the moment is 'Unix Makefiles'")
|
message(FATAL_ERROR "The only supported CMake generator at the moment is 'Unix Makefiles'")
|
||||||
endif()
|
endif()
|
||||||
@@ -9,7 +10,7 @@ endif()
|
|||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
project(LEAN CXX C)
|
project(LEAN CXX C)
|
||||||
set(LEAN_VERSION_MAJOR 4)
|
set(LEAN_VERSION_MAJOR 4)
|
||||||
set(LEAN_VERSION_MINOR 9)
|
set(LEAN_VERSION_MINOR 12)
|
||||||
set(LEAN_VERSION_PATCH 0)
|
set(LEAN_VERSION_PATCH 0)
|
||||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||||
@@ -73,6 +74,7 @@ option(USE_GMP "USE_GMP" ON)
|
|||||||
|
|
||||||
# development-specific options
|
# development-specific options
|
||||||
option(CHECK_OLEAN_VERSION "Only load .olean files compiled with the current version of Lean" OFF)
|
option(CHECK_OLEAN_VERSION "Only load .olean files compiled with the current version of Lean" OFF)
|
||||||
|
option(USE_LAKE "Use Lake instead of lean.mk for building core libs from language server" OFF)
|
||||||
|
|
||||||
set(LEAN_EXTRA_MAKE_OPTS "" CACHE STRING "extra options to lean --make")
|
set(LEAN_EXTRA_MAKE_OPTS "" CACHE STRING "extra options to lean --make")
|
||||||
set(LEANC_CC ${CMAKE_C_COMPILER} CACHE STRING "C compiler to use in `leanc`")
|
set(LEANC_CC ${CMAKE_C_COMPILER} CACHE STRING "C compiler to use in `leanc`")
|
||||||
@@ -241,6 +243,15 @@ if("${USE_GMP}" MATCHES "ON")
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Emscripten")
|
||||||
|
# LibUV
|
||||||
|
find_package(LibUV 1.0.0 REQUIRED)
|
||||||
|
include_directories(${LIBUV_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
if(NOT LEAN_STANDALONE)
|
||||||
|
string(APPEND LEAN_EXTRA_LINKER_FLAGS " ${LIBUV_LIBRARIES}")
|
||||||
|
endif()
|
||||||
|
|
||||||
# ccache
|
# ccache
|
||||||
if(CCACHE AND NOT CMAKE_CXX_COMPILER_LAUNCHER AND NOT CMAKE_C_COMPILER_LAUNCHER)
|
if(CCACHE AND NOT CMAKE_CXX_COMPILER_LAUNCHER AND NOT CMAKE_C_COMPILER_LAUNCHER)
|
||||||
find_program(CCACHE_PATH ccache)
|
find_program(CCACHE_PATH ccache)
|
||||||
@@ -299,11 +310,11 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|||||||
cmake_path(GET ZLIB_LIBRARY PARENT_PATH ZLIB_LIBRARY_PARENT_PATH)
|
cmake_path(GET ZLIB_LIBRARY PARENT_PATH ZLIB_LIBRARY_PARENT_PATH)
|
||||||
string(APPEND LEANSHARED_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
|
string(APPEND LEANSHARED_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
|
||||||
endif()
|
endif()
|
||||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lleanrt")
|
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lStd -lLean -lleanrt")
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lnodefs.js -lleanrt")
|
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lStd -lLean -lnodefs.js -lleanrt")
|
||||||
else()
|
else()
|
||||||
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
|
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -lStd -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(LEAN_CXX_STDLIB "-lstdc++" CACHE STRING "C++ stdlib linker flags")
|
set(LEAN_CXX_STDLIB "-lstdc++" CACHE STRING "C++ stdlib linker flags")
|
||||||
@@ -371,6 +382,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
|||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec")
|
string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec")
|
||||||
string(APPEND INIT_SHARED_LINKER_FLAGS " -install_name @rpath/libInit_shared.dylib")
|
string(APPEND INIT_SHARED_LINKER_FLAGS " -install_name @rpath/libInit_shared.dylib")
|
||||||
|
string(APPEND LEANSHARED_1_LINKER_FLAGS " -install_name @rpath/libleanshared_1.dylib")
|
||||||
string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib")
|
string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib")
|
||||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
@@ -400,8 +412,8 @@ endif()
|
|||||||
# executable or `leanshared`, plugins would try to look them up at load time (even though they
|
# executable or `leanshared`, plugins would try to look them up at load time (even though they
|
||||||
# are already loaded) and probably fail unless we set up LD_LIBRARY_PATH.
|
# are already loaded) and probably fail unless we set up LD_LIBRARY_PATH.
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||||
# import library created by the `leanshared` target
|
# import libraries created by the stdlib.make targets
|
||||||
string(APPEND LEANC_SHARED_LINKER_FLAGS " -lInit_shared -lleanshared")
|
string(APPEND LEANC_SHARED_LINKER_FLAGS " -lInit_shared -lleanshared_1 -lleanshared")
|
||||||
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
|
||||||
string(APPEND LEANC_SHARED_LINKER_FLAGS " -Wl,-undefined,dynamic_lookup")
|
string(APPEND LEANC_SHARED_LINKER_FLAGS " -Wl,-undefined,dynamic_lookup")
|
||||||
endif()
|
endif()
|
||||||
@@ -458,6 +470,22 @@ if(CMAKE_OSX_SYSROOT AND NOT LEAN_STANDALONE)
|
|||||||
string(APPEND LEANC_EXTRA_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
string(APPEND LEANC_EXTRA_FLAGS " ${CMAKE_CXX_SYSROOT_FLAG}${CMAKE_OSX_SYSROOT}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(initialize)
|
||||||
|
add_subdirectory(shell)
|
||||||
|
# to be included in `leanshared` but not the smaller `leanshared_1` (as it would pull
|
||||||
|
# in the world)
|
||||||
|
add_library(leaninitialize STATIC $<TARGET_OBJECTS:initialize>)
|
||||||
|
set_target_properties(leaninitialize PROPERTIES
|
||||||
|
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/temp
|
||||||
|
OUTPUT_NAME leaninitialize)
|
||||||
|
add_library(leanshell STATIC util/shell.cpp)
|
||||||
|
set_target_properties(leanshell PROPERTIES
|
||||||
|
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/temp
|
||||||
|
OUTPUT_NAME leanshell)
|
||||||
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--whole-archive -lleanmanifest -Wl,--no-whole-archive")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(${STAGE} GREATER 1)
|
if(${STAGE} GREATER 1)
|
||||||
# reuse C++ parts, which don't change
|
# reuse C++ parts, which don't change
|
||||||
add_library(leanrt_initial-exec STATIC IMPORTED)
|
add_library(leanrt_initial-exec STATIC IMPORTED)
|
||||||
@@ -466,13 +494,17 @@ if(${STAGE} GREATER 1)
|
|||||||
add_library(leanrt STATIC IMPORTED)
|
add_library(leanrt STATIC IMPORTED)
|
||||||
set_target_properties(leanrt PROPERTIES
|
set_target_properties(leanrt PROPERTIES
|
||||||
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/lean/libleanrt.a")
|
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/lean/libleanrt.a")
|
||||||
|
add_library(leancpp_1 STATIC IMPORTED)
|
||||||
|
set_target_properties(leancpp_1 PROPERTIES
|
||||||
|
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/temp/libleancpp_1.a")
|
||||||
add_library(leancpp STATIC IMPORTED)
|
add_library(leancpp STATIC IMPORTED)
|
||||||
set_target_properties(leancpp PROPERTIES
|
set_target_properties(leancpp PROPERTIES
|
||||||
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a")
|
IMPORTED_LOCATION "${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a")
|
||||||
add_custom_target(copy-leancpp
|
add_custom_target(copy-leancpp
|
||||||
COMMAND cmake -E copy_if_different "${PREV_STAGE}/runtime/libleanrt_initial-exec.a" "${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a"
|
COMMAND cmake -E copy_if_different "${PREV_STAGE}/runtime/libleanrt_initial-exec.a" "${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a"
|
||||||
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/lean/libleanrt.a" "${CMAKE_BINARY_DIR}/lib/lean/libleanrt.a"
|
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/lean/libleanrt.a" "${CMAKE_BINARY_DIR}/lib/lean/libleanrt.a"
|
||||||
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/lean/libleancpp.a" "${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a")
|
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/lean/libleancpp.a" "${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a"
|
||||||
|
COMMAND cmake -E copy_if_different "${PREV_STAGE}/lib/temp/libleancpp_1.a" "${CMAKE_BINARY_DIR}/lib/temp/libleancpp_1.a")
|
||||||
add_dependencies(leancpp copy-leancpp)
|
add_dependencies(leancpp copy-leancpp)
|
||||||
if(LLVM)
|
if(LLVM)
|
||||||
add_custom_target(copy-lean-h-bc
|
add_custom_target(copy-lean-h-bc
|
||||||
@@ -492,14 +524,23 @@ else()
|
|||||||
set(LEAN_OBJS ${LEAN_OBJS} $<TARGET_OBJECTS:constructions>)
|
set(LEAN_OBJS ${LEAN_OBJS} $<TARGET_OBJECTS:constructions>)
|
||||||
add_subdirectory(library/compiler)
|
add_subdirectory(library/compiler)
|
||||||
set(LEAN_OBJS ${LEAN_OBJS} $<TARGET_OBJECTS:compiler>)
|
set(LEAN_OBJS ${LEAN_OBJS} $<TARGET_OBJECTS:compiler>)
|
||||||
add_subdirectory(initialize)
|
|
||||||
set(LEAN_OBJS ${LEAN_OBJS} $<TARGET_OBJECTS:initialize>)
|
|
||||||
|
|
||||||
add_library(leancpp STATIC ${LEAN_OBJS})
|
# leancpp without `initialize` (see `leaninitialize` above)
|
||||||
|
add_library(leancpp_1 STATIC ${LEAN_OBJS})
|
||||||
|
set_target_properties(leancpp_1 PROPERTIES
|
||||||
|
ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib/temp
|
||||||
|
OUTPUT_NAME leancpp_1)
|
||||||
|
add_library(leancpp STATIC ${LEAN_OBJS} $<TARGET_OBJECTS:initialize>)
|
||||||
set_target_properties(leancpp PROPERTIES
|
set_target_properties(leancpp PROPERTIES
|
||||||
OUTPUT_NAME leancpp)
|
OUTPUT_NAME leancpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if((${STAGE} GREATER 0) AND CADICAL)
|
||||||
|
add_custom_target(copy-cadical
|
||||||
|
COMMAND cmake -E copy_if_different "${CADICAL}" "${CMAKE_BINARY_DIR}/bin/cadical${CMAKE_EXECUTABLE_SUFFIX}")
|
||||||
|
add_dependencies(leancpp copy-cadical)
|
||||||
|
endif()
|
||||||
|
|
||||||
# MSYS2 bash usually handles Windows paths relatively well, but not when putting them in the PATH
|
# MSYS2 bash usually handles Windows paths relatively well, but not when putting them in the PATH
|
||||||
string(REGEX REPLACE "^([a-zA-Z]):" "/\\1" LEAN_BIN "${CMAKE_BINARY_DIR}/bin")
|
string(REGEX REPLACE "^([a-zA-Z]):" "/\\1" LEAN_BIN "${CMAKE_BINARY_DIR}/bin")
|
||||||
|
|
||||||
@@ -507,25 +548,12 @@ string(REGEX REPLACE "^([a-zA-Z]):" "/\\1" LEAN_BIN "${CMAKE_BINARY_DIR}/bin")
|
|||||||
# (also looks nicer in the build log)
|
# (also looks nicer in the build log)
|
||||||
file(RELATIVE_PATH LIB ${LEAN_SOURCE_DIR} ${CMAKE_BINARY_DIR}/lib)
|
file(RELATIVE_PATH LIB ${LEAN_SOURCE_DIR} ${CMAKE_BINARY_DIR}/lib)
|
||||||
|
|
||||||
# set up libInit_shared only on Windows; see also stdlib.make.in
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
|
||||||
set(INIT_SHARED_LINKER_FLAGS "-Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libInit.a.export ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a -Wl,--no-whole-archive -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libInit_shared.dll.a")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
|
||||||
set(LEANSHARED_LINKER_FLAGS "-Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libInit.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libLean.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
|
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
|
||||||
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libLean.a.export -lleancpp -Wl,--no-whole-archive -lInit_shared -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libleanshared.dll.a")
|
|
||||||
else()
|
|
||||||
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive -lInit -lLean -lleancpp -Wl,--no-whole-archive ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
# We do not use dynamic linking via leanshared for Emscripten to keep things
|
# We do not use dynamic linking via leanshared for Emscripten to keep things
|
||||||
# simple. (And we are not interested in `Lake` anyway.) To use dynamic
|
# simple. (And we are not interested in `Lake` anyway.) To use dynamic
|
||||||
# linking, we would probably have to set MAIN_MODULE=2 on `leanshared`,
|
# linking, we would probably have to set MAIN_MODULE=2 on `leanshared`,
|
||||||
# SIDE_MODULE=2 on `lean`, and set CMAKE_SHARED_LIBRARY_SUFFIX to ".js".
|
# SIDE_MODULE=2 on `lean`, and set CMAKE_SHARED_LIBRARY_SUFFIX to ".js".
|
||||||
string(APPEND LEAN_EXE_LINKER_FLAGS " ${TOOLCHAIN_STATIC_LINKER_FLAGS} ${EMSCRIPTEN_SETTINGS} -lnodefs.js -s EXIT_RUNTIME=1 -s MAIN_MODULE=1 -s LINKABLE=1 -s EXPORT_ALL=1")
|
string(APPEND LEAN_EXE_LINKER_FLAGS " ${LIB}/temp/libleanshell.a ${TOOLCHAIN_STATIC_LINKER_FLAGS} ${EMSCRIPTEN_SETTINGS} -lnodefs.js -s EXIT_RUNTIME=1 -s MAIN_MODULE=1 -s LINKABLE=1 -s EXPORT_ALL=1")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Build the compiler using the bootstrapped C sources for stage0, and use
|
# Build the compiler using the bootstrapped C sources for stage0, and use
|
||||||
@@ -539,7 +567,7 @@ add_custom_target(make_stdlib ALL
|
|||||||
# The actual rule is in a separate makefile because we want to prefix it with '+' to use the Make job server
|
# The actual rule is in a separate makefile because we want to prefix it with '+' to use the Make job server
|
||||||
# for a parallelized nested build, but CMake doesn't let us do that.
|
# for a parallelized nested build, but CMake doesn't let us do that.
|
||||||
# We use `lean` from the previous stage, but `leanc`, headers, etc. from the current stage
|
# We use `lean` from the previous stage, but `leanc`, headers, etc. from the current stage
|
||||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Lean
|
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Std Lean
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
||||||
# if we have LLVM enabled, then build `lean.h.bc` which has the LLVM bitcode
|
# if we have LLVM enabled, then build `lean.h.bc` which has the LLVM bitcode
|
||||||
@@ -570,18 +598,14 @@ else()
|
|||||||
|
|
||||||
add_custom_target(leanshared ALL
|
add_custom_target(leanshared ALL
|
||||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||||
DEPENDS Init_shared leancpp
|
DEPENDS Init_shared leancpp_1 leancpp leanshell leaninitialize
|
||||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make leanshared
|
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make leanshared
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
||||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lInit_shared -lleanshared")
|
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lInit_shared -lleanshared_1 -lleanshared")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(${STAGE} GREATER 0 AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||||
if(NOT EXISTS ${LEAN_SOURCE_DIR}/lake/Lake.lean)
|
|
||||||
message(FATAL_ERROR "src/lake does not exist. Please check out the Lake submodule using `git submodule update --init src/lake`.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_custom_target(lake ALL
|
add_custom_target(lake ALL
|
||||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||||
DEPENDS leanshared
|
DEPENDS leanshared
|
||||||
@@ -615,7 +639,9 @@ file(COPY ${LEAN_SOURCE_DIR}/bin/leanmake DESTINATION ${CMAKE_BINARY_DIR}/bin)
|
|||||||
|
|
||||||
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/" USE_SOURCE_PERMISSIONS DESTINATION bin)
|
install(DIRECTORY "${CMAKE_BINARY_DIR}/bin/" USE_SOURCE_PERMISSIONS DESTINATION bin)
|
||||||
|
|
||||||
add_subdirectory(shell)
|
if (${STAGE} GREATER 0 AND CADICAL)
|
||||||
|
install(PROGRAMS "${CADICAL}" DESTINATION bin)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_custom_target(clean-stdlib
|
add_custom_target(clean-stdlib
|
||||||
COMMAND rm -rf "${CMAKE_BINARY_DIR}/lib" || true)
|
COMMAND rm -rf "${CMAKE_BINARY_DIR}/lib" || true)
|
||||||
@@ -658,3 +684,9 @@ endif()
|
|||||||
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
|
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
|
||||||
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE "${CMAKE_EXE_LINKER_FLAGS_MAKE}")
|
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE "${CMAKE_EXE_LINKER_FLAGS_MAKE}")
|
||||||
configure_file(${LEAN_SOURCE_DIR}/stdlib.make.in ${CMAKE_BINARY_DIR}/stdlib.make)
|
configure_file(${LEAN_SOURCE_DIR}/stdlib.make.in ${CMAKE_BINARY_DIR}/stdlib.make)
|
||||||
|
|
||||||
|
if(USE_LAKE AND STAGE EQUAL 1)
|
||||||
|
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/lakefile.toml)
|
||||||
|
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/../tests/lakefile.toml)
|
||||||
|
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/../lakefile.toml)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ theorem apply_ite (f : α → β) (P : Prop) [Decidable P] (x y : α) :
|
|||||||
-- We don't mark this as `simp` as it is already handled by `ite_eq_right_iff`.
|
-- We don't mark this as `simp` as it is already handled by `ite_eq_right_iff`.
|
||||||
theorem ite_some_none_eq_none [Decidable P] :
|
theorem ite_some_none_eq_none [Decidable P] :
|
||||||
(if P then some x else none) = none ↔ ¬ P := by
|
(if P then some x else none) = none ↔ ¬ P := by
|
||||||
simp only [ite_eq_right_iff]
|
simp only [ite_eq_right_iff, reduceCtorEq]
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
@[simp] theorem ite_some_none_eq_some [Decidable P] :
|
@[simp] theorem ite_some_none_eq_some [Decidable P] :
|
||||||
@@ -67,12 +67,8 @@ theorem ite_some_none_eq_none [Decidable P] :
|
|||||||
-- This is not marked as `simp` as it is already handled by `dite_eq_right_iff`.
|
-- This is not marked as `simp` as it is already handled by `dite_eq_right_iff`.
|
||||||
theorem dite_some_none_eq_none [Decidable P] {x : P → α} :
|
theorem dite_some_none_eq_none [Decidable P] {x : P → α} :
|
||||||
(if h : P then some (x h) else none) = none ↔ ¬P := by
|
(if h : P then some (x h) else none) = none ↔ ¬P := by
|
||||||
simp only [dite_eq_right_iff]
|
simp
|
||||||
rfl
|
|
||||||
|
|
||||||
@[simp] theorem dite_some_none_eq_some [Decidable P] {x : P → α} {y : α} :
|
@[simp] theorem dite_some_none_eq_some [Decidable P] {x : P → α} {y : α} :
|
||||||
(if h : P then some (x h) else none) = some y ↔ ∃ h : P, x h = y := by
|
(if h : P then some (x h) else none) = some y ↔ ∃ h : P, x h = y := by
|
||||||
by_cases h : P <;> simp only [h, dite_cond_eq_true, dite_cond_eq_false, Option.some.injEq,
|
by_cases h : P <;> simp [h]
|
||||||
false_iff, not_exists]
|
|
||||||
case pos => exact ⟨fun h_eq ↦ Exists.intro h h_eq, fun h_exists => h_exists.2⟩
|
|
||||||
case neg => exact fun h_false _ ↦ h_false
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ protected def adapt {ε' α : Type u} (f : ε → ε') : ExceptT ε m α → Exc
|
|||||||
end ExceptT
|
end ExceptT
|
||||||
|
|
||||||
@[always_inline]
|
@[always_inline]
|
||||||
instance (m : Type u → Type v) (ε₁ : Type u) (ε₂ : Type u) [Monad m] [MonadExceptOf ε₁ m] : MonadExceptOf ε₁ (ExceptT ε₂ m) where
|
instance (m : Type u → Type v) (ε₁ : Type u) (ε₂ : Type u) [MonadExceptOf ε₁ m] : MonadExceptOf ε₁ (ExceptT ε₂ m) where
|
||||||
throw e := ExceptT.mk <| throwThe ε₁ e
|
throw e := ExceptT.mk <| throwThe ε₁ e
|
||||||
tryCatch x handle := ExceptT.mk <| tryCatchThe ε₁ x handle
|
tryCatch x handle := ExceptT.mk <| tryCatchThe ε₁ x handle
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ instance : Monad (ExceptCpsT ε m) where
|
|||||||
bind x f := fun _ k₁ k₂ => x _ (fun a => f a _ k₁ k₂) k₂
|
bind x f := fun _ k₁ k₂ => x _ (fun a => f a _ k₁ k₂) k₂
|
||||||
|
|
||||||
instance : LawfulMonad (ExceptCpsT σ m) := by
|
instance : LawfulMonad (ExceptCpsT σ m) := by
|
||||||
refine' { .. } <;> intros <;> rfl
|
refine LawfulMonad.mk' _ ?_ ?_ ?_ <;> intros <;> rfl
|
||||||
|
|
||||||
instance : MonadExceptOf ε (ExceptCpsT ε m) where
|
instance : MonadExceptOf ε (ExceptCpsT ε m) where
|
||||||
throw e := fun _ _ k => k e
|
throw e := fun _ _ k => k e
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import Init.Meta
|
|||||||
|
|
||||||
open Function
|
open Function
|
||||||
|
|
||||||
@[simp] theorem monadLift_self [Monad m] (x : m α) : monadLift x = x :=
|
@[simp] theorem monadLift_self {m : Type u → Type v} (x : m α) : monadLift x = x :=
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -153,7 +153,7 @@ namespace Id
|
|||||||
@[simp] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
@[simp] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
|
||||||
|
|
||||||
instance : LawfulMonad Id := by
|
instance : LawfulMonad Id := by
|
||||||
refine' { .. } <;> intros <;> rfl
|
refine LawfulMonad.mk' _ ?_ ?_ ?_ <;> intros <;> rfl
|
||||||
|
|
||||||
end Id
|
end Id
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ open Function
|
|||||||
|
|
||||||
namespace ExceptT
|
namespace ExceptT
|
||||||
|
|
||||||
theorem ext [Monad m] {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
|
||||||
simp [run] at h
|
simp [run] at h
|
||||||
assumption
|
assumption
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ theorem run_bind [Monad m] (x : ExceptT ε m α)
|
|||||||
protected theorem seq_eq {α β ε : Type u} [Monad m] (mf : ExceptT ε m (α → β)) (x : ExceptT ε m α) : mf <*> x = mf >>= fun f => f <$> x :=
|
protected theorem seq_eq {α β ε : Type u} [Monad m] (mf : ExceptT ε m (α → β)) (x : ExceptT ε m α) : mf <*> x = mf >>= fun f => f <$> x :=
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
protected theorem bind_pure_comp [Monad m] [LawfulMonad m] (f : α → β) (x : ExceptT ε m α) : x >>= pure ∘ f = f <$> x := by
|
protected theorem bind_pure_comp [Monad m] (f : α → β) (x : ExceptT ε m α) : x >>= pure ∘ f = f <$> x := by
|
||||||
intros; rfl
|
intros; rfl
|
||||||
|
|
||||||
protected theorem seqLeft_eq {α β ε : Type u} {m : Type u → Type v} [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x <* y = const β <$> x <*> y := by
|
protected theorem seqLeft_eq {α β ε : Type u} {m : Type u → Type v} [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x <* y = const β <$> x <*> y := by
|
||||||
@@ -188,23 +188,23 @@ theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
|||||||
|
|
||||||
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||||
|
|
||||||
@[simp] theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α → StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
|
theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α → StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
|
||||||
simp [StateT.lift, StateT.run, bind, StateT.bind]
|
simp [StateT.lift, StateT.run, bind, StateT.bind]
|
||||||
|
|
||||||
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
||||||
|
|
||||||
@[simp] theorem run_monadMap [Monad m] [MonadFunctor n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ)
|
@[simp] theorem run_monadMap [MonadFunctor n m] (f : {β : Type u} → n β → n β) (x : StateT σ m α) (s : σ) :
|
||||||
: (monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
(monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
|
||||||
|
|
||||||
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α → β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
|
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α → β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
|
||||||
show (f >>= fun g => g <$> x).run s = _
|
show (f >>= fun g => g <$> x).run s = _
|
||||||
simp
|
simp
|
||||||
|
|
||||||
@[simp] theorem run_seqRight [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x *> y).run s = (x.run s >>= fun p => y.run p.2) := by
|
@[simp] theorem run_seqRight [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x *> y).run s = (x.run s >>= fun p => y.run p.2) := by
|
||||||
show (x >>= fun _ => y).run s = _
|
show (x >>= fun _ => y).run s = _
|
||||||
simp
|
simp
|
||||||
|
|
||||||
@[simp] theorem run_seqLeft {α β σ : Type u} [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x <* y).run s = (x.run s >>= fun p => y.run p.2 >>= fun p' => pure (p.1, p'.2)) := by
|
@[simp] theorem run_seqLeft {α β σ : Type u} [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x <* y).run s = (x.run s >>= fun p => y.run p.2 >>= fun p' => pure (p.1, p'.2)) := by
|
||||||
show (x >>= fun a => y >>= fun _ => pure a).run s = _
|
show (x >>= fun a => y >>= fun _ => pure a).run s = _
|
||||||
simp
|
simp
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ instance : MonadExceptOf Unit (OptionT m) where
|
|||||||
throw := fun _ => OptionT.fail
|
throw := fun _ => OptionT.fail
|
||||||
tryCatch := OptionT.tryCatch
|
tryCatch := OptionT.tryCatch
|
||||||
|
|
||||||
instance (ε : Type u) [Monad m] [MonadExceptOf ε m] : MonadExceptOf ε (OptionT m) where
|
instance (ε : Type u) [MonadExceptOf ε m] : MonadExceptOf ε (OptionT m) where
|
||||||
throw e := OptionT.mk <| throwThe ε e
|
throw e := OptionT.mk <| throwThe ε e
|
||||||
tryCatch x handle := OptionT.mk <| tryCatchThe ε x handle
|
tryCatch x handle := OptionT.mk <| tryCatchThe ε x handle
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ instance : MonadControl m (ReaderT ρ m) where
|
|||||||
restoreM x _ := x
|
restoreM x _ := x
|
||||||
|
|
||||||
@[always_inline]
|
@[always_inline]
|
||||||
instance ReaderT.tryFinally [MonadFinally m] [Monad m] : MonadFinally (ReaderT ρ m) where
|
instance ReaderT.tryFinally [MonadFinally m] : MonadFinally (ReaderT ρ m) where
|
||||||
tryFinally' x h ctx := tryFinally' (x ctx) (fun a? => h a? ctx)
|
tryFinally' x h ctx := tryFinally' (x ctx) (fun a? => h a? ctx)
|
||||||
|
|
||||||
@[reducible] def ReaderM (ρ : Type u) := ReaderT ρ Id
|
@[reducible] def ReaderM (ρ : Type u) := ReaderT ρ Id
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ protected def lift {α : Type u} (t : m α) : StateT σ m α :=
|
|||||||
instance : MonadLift m (StateT σ m) := ⟨StateT.lift⟩
|
instance : MonadLift m (StateT σ m) := ⟨StateT.lift⟩
|
||||||
|
|
||||||
@[always_inline]
|
@[always_inline]
|
||||||
instance (σ m) [Monad m] : MonadFunctor m (StateT σ m) := ⟨fun f x s => f (x s)⟩
|
instance (σ m) : MonadFunctor m (StateT σ m) := ⟨fun f x s => f (x s)⟩
|
||||||
|
|
||||||
@[always_inline]
|
@[always_inline]
|
||||||
instance (ε) [MonadExceptOf ε m] : MonadExceptOf ε (StateT σ m) := {
|
instance (ε) [MonadExceptOf ε m] : MonadExceptOf ε (StateT σ m) := {
|
||||||
|
|||||||
@@ -14,16 +14,18 @@ def StateCpsT (σ : Type u) (m : Type u → Type v) (α : Type u) := (δ : Type
|
|||||||
|
|
||||||
namespace StateCpsT
|
namespace StateCpsT
|
||||||
|
|
||||||
|
variable {α σ : Type u} {m : Type u → Type v}
|
||||||
|
|
||||||
@[always_inline, inline]
|
@[always_inline, inline]
|
||||||
def runK {α σ : Type u} {m : Type u → Type v} (x : StateCpsT σ m α) (s : σ) (k : α → σ → m β) : m β :=
|
def runK (x : StateCpsT σ m α) (s : σ) (k : α → σ → m β) : m β :=
|
||||||
x _ s k
|
x _ s k
|
||||||
|
|
||||||
@[always_inline, inline]
|
@[always_inline, inline]
|
||||||
def run {α σ : Type u} {m : Type u → Type v} [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
|
def run [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
|
||||||
runK x s (fun a s => pure (a, s))
|
runK x s (fun a s => pure (a, s))
|
||||||
|
|
||||||
@[always_inline, inline]
|
@[always_inline, inline]
|
||||||
def run' {α σ : Type u} {m : Type u → Type v} [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
|
def run' [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
|
||||||
runK x s (fun a _ => pure a)
|
runK x s (fun a _ => pure a)
|
||||||
|
|
||||||
@[always_inline]
|
@[always_inline]
|
||||||
@@ -33,7 +35,7 @@ instance : Monad (StateCpsT σ m) where
|
|||||||
bind x f := fun δ s k => x δ s fun a s => f a δ s k
|
bind x f := fun δ s k => x δ s fun a s => f a δ s k
|
||||||
|
|
||||||
instance : LawfulMonad (StateCpsT σ m) := by
|
instance : LawfulMonad (StateCpsT σ m) := by
|
||||||
refine' { .. } <;> intros <;> rfl
|
refine LawfulMonad.mk' _ ?_ ?_ ?_ <;> intros <;> rfl
|
||||||
|
|
||||||
@[always_inline]
|
@[always_inline]
|
||||||
instance : MonadStateOf σ (StateCpsT σ m) where
|
instance : MonadStateOf σ (StateCpsT σ m) where
|
||||||
@@ -48,29 +50,29 @@ protected def lift [Monad m] (x : m α) : StateCpsT σ m α :=
|
|||||||
instance [Monad m] : MonadLift m (StateCpsT σ m) where
|
instance [Monad m] : MonadLift m (StateCpsT σ m) where
|
||||||
monadLift := StateCpsT.lift
|
monadLift := StateCpsT.lift
|
||||||
|
|
||||||
@[simp] theorem runK_pure {m : Type u → Type v} (a : α) (s : σ) (k : α → σ → m β) : (pure a : StateCpsT σ m α).runK s k = k a s := rfl
|
@[simp] theorem runK_pure (a : α) (s : σ) (k : α → σ → m β) : (pure a : StateCpsT σ m α).runK s k = k a s := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_get {m : Type u → Type v} (s : σ) (k : σ → σ → m β) : (get : StateCpsT σ m σ).runK s k = k s s := rfl
|
@[simp] theorem runK_get (s : σ) (k : σ → σ → m β) : (get : StateCpsT σ m σ).runK s k = k s s := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_set {m : Type u → Type v} (s s' : σ) (k : PUnit → σ → m β) : (set s' : StateCpsT σ m PUnit).runK s k = k ⟨⟩ s' := rfl
|
@[simp] theorem runK_set (s s' : σ) (k : PUnit → σ → m β) : (set s' : StateCpsT σ m PUnit).runK s k = k ⟨⟩ s' := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_modify {m : Type u → Type v} (f : σ → σ) (s : σ) (k : PUnit → σ → m β) : (modify f : StateCpsT σ m PUnit).runK s k = k ⟨⟩ (f s) := rfl
|
@[simp] theorem runK_modify (f : σ → σ) (s : σ) (k : PUnit → σ → m β) : (modify f : StateCpsT σ m PUnit).runK s k = k ⟨⟩ (f s) := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) (k : α → σ → m β) : (StateCpsT.lift x : StateCpsT σ m α).runK s k = x >>= (k . s) := rfl
|
@[simp] theorem runK_lift [Monad m] (x : m α) (s : σ) (k : α → σ → m β) : (StateCpsT.lift x : StateCpsT σ m α).runK s k = x >>= (k . s) := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_monadLift {σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) (k : α → σ → m β)
|
@[simp] theorem runK_monadLift [Monad m] [MonadLiftT n m] (x : n α) (s : σ) (k : α → σ → m β)
|
||||||
: (monadLift x : StateCpsT σ m α).runK s k = (monadLift x : m α) >>= (k . s) := rfl
|
: (monadLift x : StateCpsT σ m α).runK s k = (monadLift x : m α) >>= (k . s) := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_bind_pure {α σ : Type u} [Monad m] (a : α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (pure a >>= f).runK s k = (f a).runK s k := rfl
|
@[simp] theorem runK_bind_pure (a : α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (pure a >>= f).runK s k = (f a).runK s k := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_bind_lift {α σ : Type u} [Monad m] (x : m α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ)
|
@[simp] theorem runK_bind_lift [Monad m] (x : m α) (f : α → StateCpsT σ m β) (s : σ) (k : β → σ → m γ)
|
||||||
: (StateCpsT.lift x >>= f).runK s k = x >>= fun a => (f a).runK s k := rfl
|
: (StateCpsT.lift x >>= f).runK s k = x >>= fun a => (f a).runK s k := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_bind_get {σ : Type u} [Monad m] (f : σ → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (get >>= f).runK s k = (f s).runK s k := rfl
|
@[simp] theorem runK_bind_get (f : σ → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (get >>= f).runK s k = (f s).runK s k := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_bind_set {σ : Type u} [Monad m] (f : PUnit → StateCpsT σ m β) (s s' : σ) (k : β → σ → m γ) : (set s' >>= f).runK s k = (f ⟨⟩).runK s' k := rfl
|
@[simp] theorem runK_bind_set (f : PUnit → StateCpsT σ m β) (s s' : σ) (k : β → σ → m γ) : (set s' >>= f).runK s k = (f ⟨⟩).runK s' k := rfl
|
||||||
|
|
||||||
@[simp] theorem runK_bind_modify {σ : Type u} [Monad m] (f : σ → σ) (g : PUnit → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (modify f >>= g).runK s k = (g ⟨⟩).runK (f s) k := rfl
|
@[simp] theorem runK_bind_modify (f : σ → σ) (g : PUnit → StateCpsT σ m β) (s : σ) (k : β → σ → m γ) : (modify f >>= g).runK s k = (g ⟨⟩).runK (f s) k := rfl
|
||||||
|
|
||||||
@[simp] theorem run_eq [Monad m] (x : StateCpsT σ m α) (s : σ) : x.run s = x.runK s (fun a s => pure (a, s)) := rfl
|
@[simp] theorem run_eq [Monad m] (x : StateCpsT σ m α) (s : σ) : x.run s = x.runK s (fun a s => pure (a, s)) := rfl
|
||||||
|
|
||||||
|
|||||||
@@ -34,22 +34,22 @@ protected def lift (x : m α) : StateRefT' ω σ m α :=
|
|||||||
|
|
||||||
instance [Monad m] : Monad (StateRefT' ω σ m) := inferInstanceAs (Monad (ReaderT _ _))
|
instance [Monad m] : Monad (StateRefT' ω σ m) := inferInstanceAs (Monad (ReaderT _ _))
|
||||||
instance : MonadLift m (StateRefT' ω σ m) := ⟨StateRefT'.lift⟩
|
instance : MonadLift m (StateRefT' ω σ m) := ⟨StateRefT'.lift⟩
|
||||||
instance (σ m) [Monad m] : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
|
instance (σ m) : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
|
||||||
instance [Alternative m] [Monad m] : Alternative (StateRefT' ω σ m) := inferInstanceAs (Alternative (ReaderT _ _))
|
instance [Alternative m] [Monad m] : Alternative (StateRefT' ω σ m) := inferInstanceAs (Alternative (ReaderT _ _))
|
||||||
|
|
||||||
@[inline]
|
@[inline]
|
||||||
protected def get [Monad m] [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
|
protected def get [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
|
||||||
fun ref => ref.get
|
fun ref => ref.get
|
||||||
|
|
||||||
@[inline]
|
@[inline]
|
||||||
protected def set [Monad m] [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
|
protected def set [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
|
||||||
fun ref => ref.set s
|
fun ref => ref.set s
|
||||||
|
|
||||||
@[inline]
|
@[inline]
|
||||||
protected def modifyGet [Monad m] [MonadLiftT (ST ω) m] (f : σ → α × σ) : StateRefT' ω σ m α :=
|
protected def modifyGet [MonadLiftT (ST ω) m] (f : σ → α × σ) : StateRefT' ω σ m α :=
|
||||||
fun ref => ref.modifyGet f
|
fun ref => ref.modifyGet f
|
||||||
|
|
||||||
instance [MonadLiftT (ST ω) m] [Monad m] : MonadStateOf σ (StateRefT' ω σ m) where
|
instance [MonadLiftT (ST ω) m] : MonadStateOf σ (StateRefT' ω σ m) where
|
||||||
get := StateRefT'.get
|
get := StateRefT'.get
|
||||||
set := StateRefT'.set
|
set := StateRefT'.set
|
||||||
modifyGet := StateRefT'.modifyGet
|
modifyGet := StateRefT'.modifyGet
|
||||||
@@ -64,5 +64,5 @@ end StateRefT'
|
|||||||
instance (ω σ : Type) (m : Type → Type) : MonadControl m (StateRefT' ω σ m) :=
|
instance (ω σ : Type) (m : Type → Type) : MonadControl m (StateRefT' ω σ m) :=
|
||||||
inferInstanceAs (MonadControl m (ReaderT _ _))
|
inferInstanceAs (MonadControl m (ReaderT _ _))
|
||||||
|
|
||||||
instance {m : Type → Type} {ω σ : Type} [MonadFinally m] [Monad m] : MonadFinally (StateRefT' ω σ m) :=
|
instance {m : Type → Type} {ω σ : Type} [MonadFinally m] : MonadFinally (StateRefT' ω σ m) :=
|
||||||
inferInstanceAs (MonadFinally (ReaderT _ _))
|
inferInstanceAs (MonadFinally (ReaderT _ _))
|
||||||
|
|||||||
@@ -36,6 +36,17 @@ and `flip (·<·)` is the greater-than relation.
|
|||||||
|
|
||||||
theorem Function.comp_def {α β δ} (f : β → δ) (g : α → β) : f ∘ g = fun x => f (g x) := rfl
|
theorem Function.comp_def {α β δ} (f : β → δ) (g : α → β) : f ∘ g = fun x => f (g x) := rfl
|
||||||
|
|
||||||
|
@[simp] theorem Function.const_comp {f : α → β} {c : γ} :
|
||||||
|
(Function.const β c ∘ f) = Function.const α c := by
|
||||||
|
rfl
|
||||||
|
@[simp] theorem Function.comp_const {f : β → γ} {b : β} :
|
||||||
|
(f ∘ Function.const α b) = Function.const α (f b) := by
|
||||||
|
rfl
|
||||||
|
@[simp] theorem Function.true_comp {f : α → β} : ((fun _ => true) ∘ f) = fun _ => true := by
|
||||||
|
rfl
|
||||||
|
@[simp] theorem Function.false_comp {f : α → β} : ((fun _ => false) ∘ f) = fun _ => false := by
|
||||||
|
rfl
|
||||||
|
|
||||||
attribute [simp] namedPattern
|
attribute [simp] namedPattern
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -468,11 +479,13 @@ class Singleton (α : outParam <| Type u) (β : Type v) where
|
|||||||
export Singleton (singleton)
|
export Singleton (singleton)
|
||||||
|
|
||||||
/-- `insert x ∅ = {x}` -/
|
/-- `insert x ∅ = {x}` -/
|
||||||
class IsLawfulSingleton (α : Type u) (β : Type v) [EmptyCollection β] [Insert α β] [Singleton α β] :
|
class LawfulSingleton (α : Type u) (β : Type v) [EmptyCollection β] [Insert α β] [Singleton α β] :
|
||||||
Prop where
|
Prop where
|
||||||
/-- `insert x ∅ = {x}` -/
|
/-- `insert x ∅ = {x}` -/
|
||||||
insert_emptyc_eq (x : α) : (insert x ∅ : β) = singleton x
|
insert_emptyc_eq (x : α) : (insert x ∅ : β) = singleton x
|
||||||
export IsLawfulSingleton (insert_emptyc_eq)
|
export LawfulSingleton (insert_emptyc_eq)
|
||||||
|
|
||||||
|
attribute [simp] insert_emptyc_eq
|
||||||
|
|
||||||
/-- Type class used to implement the notation `{ a ∈ c | p a }` -/
|
/-- Type class used to implement the notation `{ a ∈ c | p a }` -/
|
||||||
class Sep (α : outParam <| Type u) (γ : Type v) where
|
class Sep (α : outParam <| Type u) (γ : Type v) where
|
||||||
@@ -642,7 +655,7 @@ instance : LawfulBEq String := inferInstance
|
|||||||
|
|
||||||
/-! # Logical connectives and equality -/
|
/-! # Logical connectives and equality -/
|
||||||
|
|
||||||
@[inherit_doc True.intro] def trivial : True := ⟨⟩
|
@[inherit_doc True.intro] theorem trivial : True := ⟨⟩
|
||||||
|
|
||||||
theorem mt {a b : Prop} (h₁ : a → b) (h₂ : ¬b) : ¬a :=
|
theorem mt {a b : Prop} (h₁ : a → b) (h₂ : ¬b) : ¬a :=
|
||||||
fun ha => h₂ (h₁ ha)
|
fun ha => h₂ (h₁ ha)
|
||||||
@@ -701,7 +714,7 @@ theorem Ne.elim (h : a ≠ b) : a = b → False := h
|
|||||||
|
|
||||||
theorem Ne.irrefl (h : a ≠ a) : False := h rfl
|
theorem Ne.irrefl (h : a ≠ a) : False := h rfl
|
||||||
|
|
||||||
theorem Ne.symm (h : a ≠ b) : b ≠ a := fun h₁ => h (h₁.symm)
|
@[symm] theorem Ne.symm (h : a ≠ b) : b ≠ a := fun h₁ => h (h₁.symm)
|
||||||
|
|
||||||
theorem ne_comm {α} {a b : α} : a ≠ b ↔ b ≠ a := ⟨Ne.symm, Ne.symm⟩
|
theorem ne_comm {α} {a b : α} : a ≠ b ↔ b ≠ a := ⟨Ne.symm, Ne.symm⟩
|
||||||
|
|
||||||
@@ -754,7 +767,7 @@ noncomputable def HEq.elim {α : Sort u} {a : α} {p : α → Sort v} {b : α} (
|
|||||||
theorem HEq.subst {p : (T : Sort u) → T → Prop} (h₁ : HEq a b) (h₂ : p α a) : p β b :=
|
theorem HEq.subst {p : (T : Sort u) → T → Prop} (h₁ : HEq a b) (h₂ : p α a) : p β b :=
|
||||||
HEq.ndrecOn h₁ h₂
|
HEq.ndrecOn h₁ h₂
|
||||||
|
|
||||||
theorem HEq.symm (h : HEq a b) : HEq b a :=
|
@[symm] theorem HEq.symm (h : HEq a b) : HEq b a :=
|
||||||
h.rec (HEq.refl a)
|
h.rec (HEq.refl a)
|
||||||
|
|
||||||
theorem heq_of_eq (h : a = a') : HEq a a' :=
|
theorem heq_of_eq (h : a = a') : HEq a a' :=
|
||||||
@@ -810,15 +823,15 @@ instance : Trans Iff Iff Iff where
|
|||||||
theorem Eq.comm {a b : α} : a = b ↔ b = a := Iff.intro Eq.symm Eq.symm
|
theorem Eq.comm {a b : α} : a = b ↔ b = a := Iff.intro Eq.symm Eq.symm
|
||||||
theorem eq_comm {a b : α} : a = b ↔ b = a := Eq.comm
|
theorem eq_comm {a b : α} : a = b ↔ b = a := Eq.comm
|
||||||
|
|
||||||
theorem Iff.symm (h : a ↔ b) : b ↔ a := Iff.intro h.mpr h.mp
|
@[symm] theorem Iff.symm (h : a ↔ b) : b ↔ a := Iff.intro h.mpr h.mp
|
||||||
theorem Iff.comm: (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm
|
theorem Iff.comm: (a ↔ b) ↔ (b ↔ a) := Iff.intro Iff.symm Iff.symm
|
||||||
theorem iff_comm : (a ↔ b) ↔ (b ↔ a) := Iff.comm
|
theorem iff_comm : (a ↔ b) ↔ (b ↔ a) := Iff.comm
|
||||||
|
|
||||||
theorem And.symm : a ∧ b → b ∧ a := fun ⟨ha, hb⟩ => ⟨hb, ha⟩
|
@[symm] theorem And.symm : a ∧ b → b ∧ a := fun ⟨ha, hb⟩ => ⟨hb, ha⟩
|
||||||
theorem And.comm : a ∧ b ↔ b ∧ a := Iff.intro And.symm And.symm
|
theorem And.comm : a ∧ b ↔ b ∧ a := Iff.intro And.symm And.symm
|
||||||
theorem and_comm : a ∧ b ↔ b ∧ a := And.comm
|
theorem and_comm : a ∧ b ↔ b ∧ a := And.comm
|
||||||
|
|
||||||
theorem Or.symm : a ∨ b → b ∨ a := .rec .inr .inl
|
@[symm] theorem Or.symm : a ∨ b → b ∨ a := .rec .inr .inl
|
||||||
theorem Or.comm : a ∨ b ↔ b ∨ a := Iff.intro Or.symm Or.symm
|
theorem Or.comm : a ∨ b ↔ b ∨ a := Iff.intro Or.symm Or.symm
|
||||||
theorem or_comm : a ∨ b ↔ b ∨ a := Or.comm
|
theorem or_comm : a ∨ b ↔ b ∨ a := Or.comm
|
||||||
|
|
||||||
@@ -1089,19 +1102,30 @@ def InvImage {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β
|
|||||||
fun a₁ a₂ => r (f a₁) (f a₂)
|
fun a₁ a₂ => r (f a₁) (f a₂)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
The transitive closure `r⁺` of a relation `r` is the smallest relation which is
|
The transitive closure `TransGen r` of a relation `r` is the smallest relation which is
|
||||||
transitive and contains `r`. `r⁺ a z` if and only if there exists a sequence
|
transitive and contains `r`. `TransGen r a z` if and only if there exists a sequence
|
||||||
`a r b r ... r z` of length at least 1 connecting `a` to `z`.
|
`a r b r ... r z` of length at least 1 connecting `a` to `z`.
|
||||||
-/
|
-/
|
||||||
inductive TC {α : Sort u} (r : α → α → Prop) : α → α → Prop where
|
inductive Relation.TransGen {α : Sort u} (r : α → α → Prop) : α → α → Prop
|
||||||
/-- If `r a b` then `r⁺ a b`. This is the base case of the transitive closure. -/
|
/-- If `r a b` then `TransGen r a b`. This is the base case of the transitive closure. -/
|
||||||
| base : ∀ a b, r a b → TC r a b
|
| single {a b} : r a b → TransGen r a b
|
||||||
/-- The transitive closure is transitive. -/
|
/-- The transitive closure is transitive. -/
|
||||||
| trans : ∀ a b c, TC r a b → TC r b c → TC r a c
|
| tail {a b c} : TransGen r a b → r b c → TransGen r a c
|
||||||
|
|
||||||
|
/-- Deprecated synonym for `Relation.TransGen`. -/
|
||||||
|
@[deprecated Relation.TransGen (since := "2024-07-16")] abbrev TC := @Relation.TransGen
|
||||||
|
|
||||||
|
theorem Relation.TransGen.trans {α : Sort u} {r : α → α → Prop} {a b c} :
|
||||||
|
TransGen r a b → TransGen r b c → TransGen r a c := by
|
||||||
|
intro hab hbc
|
||||||
|
induction hbc with
|
||||||
|
| single h => exact TransGen.tail hab h
|
||||||
|
| tail _ h ih => exact TransGen.tail ih h
|
||||||
|
|
||||||
/-! # Subtype -/
|
/-! # Subtype -/
|
||||||
|
|
||||||
namespace Subtype
|
namespace Subtype
|
||||||
|
|
||||||
theorem existsOfSubtype {α : Type u} {p : α → Prop} : { x // p x } → Exists (fun x => p x)
|
theorem existsOfSubtype {α : Type u} {p : α → Prop} : { x // p x } → Exists (fun x => p x)
|
||||||
| ⟨a, h⟩ => ⟨a, h⟩
|
| ⟨a, h⟩ => ⟨a, h⟩
|
||||||
|
|
||||||
@@ -1173,7 +1197,7 @@ def Prod.lexLt [LT α] [LT β] (s : α × β) (t : α × β) : Prop :=
|
|||||||
s.1 < t.1 ∨ (s.1 = t.1 ∧ s.2 < t.2)
|
s.1 < t.1 ∨ (s.1 = t.1 ∧ s.2 < t.2)
|
||||||
|
|
||||||
instance Prod.lexLtDec
|
instance Prod.lexLtDec
|
||||||
[LT α] [LT β] [DecidableEq α] [DecidableEq β]
|
[LT α] [LT β] [DecidableEq α]
|
||||||
[(a b : α) → Decidable (a < b)] [(a b : β) → Decidable (a < b)]
|
[(a b : α) → Decidable (a < b)] [(a b : β) → Decidable (a < b)]
|
||||||
: (s t : α × β) → Decidable (Prod.lexLt s t) :=
|
: (s t : α × β) → Decidable (Prod.lexLt s t) :=
|
||||||
fun _ _ => inferInstanceAs (Decidable (_ ∨ _))
|
fun _ _ => inferInstanceAs (Decidable (_ ∨ _))
|
||||||
@@ -1191,11 +1215,20 @@ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂
|
|||||||
(f : α₁ → α₂) (g : β₁ → β₂) : α₁ × β₁ → α₂ × β₂
|
(f : α₁ → α₂) (g : β₁ → β₂) : α₁ × β₁ → α₂ × β₂
|
||||||
| (a, b) => (f a, g b)
|
| (a, b) => (f a, g b)
|
||||||
|
|
||||||
|
@[simp] theorem Prod.map_apply (f : α → β) (g : γ → δ) (x) (y) :
|
||||||
|
Prod.map f g (x, y) = (f x, g y) := rfl
|
||||||
|
@[simp] theorem Prod.map_fst (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).1 = f x.1 := rfl
|
||||||
|
@[simp] theorem Prod.map_snd (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).2 = g x.2 := rfl
|
||||||
|
|
||||||
/-! # Dependent products -/
|
/-! # Dependent products -/
|
||||||
|
|
||||||
theorem ex_of_PSigma {α : Type u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x)
|
theorem Exists.of_psigma_prop {α : Sort u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x)
|
||||||
| ⟨x, hx⟩ => ⟨x, hx⟩
|
| ⟨x, hx⟩ => ⟨x, hx⟩
|
||||||
|
|
||||||
|
@[deprecated Exists.of_psigma_prop (since := "2024-07-27")]
|
||||||
|
theorem ex_of_PSigma {α : Type u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x) :=
|
||||||
|
Exists.of_psigma_prop
|
||||||
|
|
||||||
protected theorem PSigma.eta {α : Sort u} {β : α → Sort v} {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂}
|
protected theorem PSigma.eta {α : Sort u} {β : α → Sort v} {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂}
|
||||||
(h₁ : a₁ = a₂) (h₂ : Eq.ndrec b₁ h₁ = b₂) : PSigma.mk a₁ b₁ = PSigma.mk a₂ b₂ := by
|
(h₁ : a₁ = a₂) (h₂ : Eq.ndrec b₁ h₁ = b₂) : PSigma.mk a₁ b₁ = PSigma.mk a₂ b₂ := by
|
||||||
subst h₁
|
subst h₁
|
||||||
@@ -1357,6 +1390,9 @@ theorem iff_false_right (ha : ¬a) : (b ↔ a) ↔ ¬b := Iff.comm.trans (iff_fa
|
|||||||
theorem of_iff_true (h : a ↔ True) : a := h.mpr trivial
|
theorem of_iff_true (h : a ↔ True) : a := h.mpr trivial
|
||||||
theorem iff_true_intro (h : a) : a ↔ True := iff_of_true h trivial
|
theorem iff_true_intro (h : a) : a ↔ True := iff_of_true h trivial
|
||||||
|
|
||||||
|
theorem eq_iff_true_of_subsingleton [Subsingleton α] (x y : α) : x = y ↔ True :=
|
||||||
|
iff_true_intro (Subsingleton.elim ..)
|
||||||
|
|
||||||
theorem not_of_iff_false : (p ↔ False) → ¬p := Iff.mp
|
theorem not_of_iff_false : (p ↔ False) → ¬p := Iff.mp
|
||||||
theorem iff_false_intro (h : ¬a) : a ↔ False := iff_of_false h id
|
theorem iff_false_intro (h : ¬a) : a ↔ False := iff_of_false h id
|
||||||
|
|
||||||
@@ -1528,13 +1564,13 @@ so you should consider the simpler versions if they apply:
|
|||||||
* `Quot.recOnSubsingleton`, when the target type is a `Subsingleton`
|
* `Quot.recOnSubsingleton`, when the target type is a `Subsingleton`
|
||||||
* `Quot.hrecOn`, which uses `HEq (f a) (f b)` instead of a `sound p ▸ f a = f b` assummption
|
* `Quot.hrecOn`, which uses `HEq (f a) (f b)` instead of a `sound p ▸ f a = f b` assummption
|
||||||
-/
|
-/
|
||||||
protected abbrev rec
|
@[elab_as_elim] protected abbrev rec
|
||||||
(f : (a : α) → motive (Quot.mk r a))
|
(f : (a : α) → motive (Quot.mk r a))
|
||||||
(h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b)
|
(h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b)
|
||||||
(q : Quot r) : motive q :=
|
(q : Quot r) : motive q :=
|
||||||
Eq.ndrecOn (Quot.liftIndepPr1 f h q) ((lift (Quot.indep f) (Quot.indepCoherent f h) q).2)
|
Eq.ndrecOn (Quot.liftIndepPr1 f h q) ((lift (Quot.indep f) (Quot.indepCoherent f h) q).2)
|
||||||
|
|
||||||
@[inherit_doc Quot.rec] protected abbrev recOn
|
@[inherit_doc Quot.rec, elab_as_elim] protected abbrev recOn
|
||||||
(q : Quot r)
|
(q : Quot r)
|
||||||
(f : (a : α) → motive (Quot.mk r a))
|
(f : (a : α) → motive (Quot.mk r a))
|
||||||
(h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b)
|
(h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b)
|
||||||
@@ -1545,7 +1581,7 @@ protected abbrev rec
|
|||||||
Dependent induction principle for a quotient, when the target type is a `Subsingleton`.
|
Dependent induction principle for a quotient, when the target type is a `Subsingleton`.
|
||||||
In this case the quotient's side condition is trivial so any function can be lifted.
|
In this case the quotient's side condition is trivial so any function can be lifted.
|
||||||
-/
|
-/
|
||||||
protected abbrev recOnSubsingleton
|
@[elab_as_elim] protected abbrev recOnSubsingleton
|
||||||
[h : (a : α) → Subsingleton (motive (Quot.mk r a))]
|
[h : (a : α) → Subsingleton (motive (Quot.mk r a))]
|
||||||
(q : Quot r)
|
(q : Quot r)
|
||||||
(f : (a : α) → motive (Quot.mk r a))
|
(f : (a : α) → motive (Quot.mk r a))
|
||||||
@@ -1614,7 +1650,7 @@ protected theorem ind {α : Sort u} {s : Setoid α} {motive : Quotient s → Pro
|
|||||||
|
|
||||||
/--
|
/--
|
||||||
The analogue of `Quot.liftOn`: if `f : α → β` respects the equivalence relation `≈`,
|
The analogue of `Quot.liftOn`: if `f : α → β` respects the equivalence relation `≈`,
|
||||||
then it lifts to a function on `Quotient s` such that `lift (mk a) f h = f a`.
|
then it lifts to a function on `Quotient s` such that `liftOn (mk a) f h = f a`.
|
||||||
-/
|
-/
|
||||||
protected abbrev liftOn {α : Sort u} {β : Sort v} {s : Setoid α} (q : Quotient s) (f : α → β) (c : (a b : α) → a ≈ b → f a = f b) : β :=
|
protected abbrev liftOn {α : Sort u} {β : Sort v} {s : Setoid α} (q : Quotient s) (f : α → β) (c : (a b : α) → a ≈ b → f a = f b) : β :=
|
||||||
Quot.liftOn q f c
|
Quot.liftOn q f c
|
||||||
@@ -1862,7 +1898,7 @@ instance : Subsingleton (Squash α) where
|
|||||||
/--
|
/--
|
||||||
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
|
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
|
||||||
-/
|
-/
|
||||||
class Antisymm {α : Sort u} (r : α → α → Prop) where
|
class Antisymm {α : Sort u} (r : α → α → Prop) : Prop where
|
||||||
/-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
|
/-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
|
||||||
antisymm {a b : α} : r a b → r b a → a = b
|
antisymm {a b : α} : r a b → r b a → a = b
|
||||||
|
|
||||||
|
|||||||
@@ -35,3 +35,7 @@ import Init.Data.Queue
|
|||||||
import Init.Data.Channel
|
import Init.Data.Channel
|
||||||
import Init.Data.Cast
|
import Init.Data.Cast
|
||||||
import Init.Data.Sum
|
import Init.Data.Sum
|
||||||
|
import Init.Data.BEq
|
||||||
|
import Init.Data.Subtype
|
||||||
|
import Init.Data.ULift
|
||||||
|
import Init.Data.PLift
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Authors: Dany Fabian
|
|||||||
|
|
||||||
prelude
|
prelude
|
||||||
import Init.Classical
|
import Init.Classical
|
||||||
import Init.Data.List
|
import Init.ByCases
|
||||||
|
|
||||||
namespace Lean.Data.AC
|
namespace Lean.Data.AC
|
||||||
inductive Expr
|
inductive Expr
|
||||||
@@ -146,8 +146,8 @@ theorem Context.evalList_mergeIdem (ctx : Context α) (h : ContextInformation.is
|
|||||||
| nil =>
|
| nil =>
|
||||||
simp [mergeIdem, mergeIdem.loop]
|
simp [mergeIdem, mergeIdem.loop]
|
||||||
split
|
split
|
||||||
case inl h₂ => simp [evalList, h₂, h.1, EvalInformation.evalOp]
|
next h₂ => simp [evalList, h₂, h.1, EvalInformation.evalOp]
|
||||||
rfl
|
next => rfl
|
||||||
| cons z zs =>
|
| cons z zs =>
|
||||||
by_cases h₂ : x = y
|
by_cases h₂ : x = y
|
||||||
case pos =>
|
case pos =>
|
||||||
@@ -191,11 +191,11 @@ theorem Context.evalList_insert
|
|||||||
. simp [evalList, h.1, EvalInformation.evalOp]
|
. simp [evalList, h.1, EvalInformation.evalOp]
|
||||||
| step y z zs ih =>
|
| step y z zs ih =>
|
||||||
simp [insert] at *; split
|
simp [insert] at *; split
|
||||||
case inl => rfl
|
next => rfl
|
||||||
case inr =>
|
next =>
|
||||||
split
|
split
|
||||||
case inl => simp [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
|
next => simp [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
|
||||||
case inr => simp_all [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
|
next => simp_all [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
|
||||||
|
|
||||||
theorem Context.evalList_sort_congr
|
theorem Context.evalList_sort_congr
|
||||||
(ctx : Context α)
|
(ctx : Context α)
|
||||||
@@ -260,7 +260,7 @@ theorem Context.evalList_sort (ctx : Context α) (h : ContextInformation.isComm
|
|||||||
simp [ContextInformation.isComm, Option.isSome] at h
|
simp [ContextInformation.isComm, Option.isSome] at h
|
||||||
match h₂ : ctx.comm with
|
match h₂ : ctx.comm with
|
||||||
| none =>
|
| none =>
|
||||||
simp only [h₂] at h
|
simp [h₂] at h
|
||||||
| some val =>
|
| some val =>
|
||||||
simp [h₂] at h
|
simp [h₂] at h
|
||||||
exact val.down
|
exact val.down
|
||||||
|
|||||||
@@ -10,5 +10,7 @@ import Init.Data.Array.BinSearch
|
|||||||
import Init.Data.Array.InsertionSort
|
import Init.Data.Array.InsertionSort
|
||||||
import Init.Data.Array.DecidableEq
|
import Init.Data.Array.DecidableEq
|
||||||
import Init.Data.Array.Mem
|
import Init.Data.Array.Mem
|
||||||
|
import Init.Data.Array.Attach
|
||||||
import Init.Data.Array.BasicAux
|
import Init.Data.Array.BasicAux
|
||||||
import Init.Data.Array.Lemmas
|
import Init.Data.Array.Lemmas
|
||||||
|
import Init.Data.Array.TakeDrop
|
||||||
|
|||||||
29
src/Init/Data/Array/Attach.lean
Normal file
29
src/Init/Data/Array/Attach.lean
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2021 Floris van Doorn. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Joachim Breitner, Mario Carneiro
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.Array.Mem
|
||||||
|
import Init.Data.List.Attach
|
||||||
|
|
||||||
|
namespace Array
|
||||||
|
|
||||||
|
/--
|
||||||
|
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||||
|
`Array {x // P x}` is the same as the input `Array α`.
|
||||||
|
-/
|
||||||
|
@[inline] private unsafe def attachWithImpl
|
||||||
|
(xs : Array α) (P : α → Prop) (_ : ∀ x ∈ xs, P x) : Array {x // P x} := unsafeCast xs
|
||||||
|
|
||||||
|
/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `xs` to produce a new array
|
||||||
|
with the same elements but in the type `{x // P x}`. -/
|
||||||
|
@[implemented_by attachWithImpl] def attachWith
|
||||||
|
(xs : Array α) (P : α → Prop) (H : ∀ x ∈ xs, P x) : Array {x // P x} :=
|
||||||
|
⟨xs.data.attachWith P fun x h => H x (Array.Mem.mk h)⟩
|
||||||
|
|
||||||
|
/-- `O(1)`. "Attach" the proof that the elements of `xs` are in `xs` to produce a new array
|
||||||
|
with the same elements but in the type `{x // x ∈ xs}`. -/
|
||||||
|
@[inline] def attach (xs : Array α) : Array {x // x ∈ xs} := xs.attachWith _ fun _ => id
|
||||||
|
|
||||||
|
end Array
|
||||||
@@ -50,6 +50,13 @@ instance : Inhabited (Array α) where
|
|||||||
def singleton (v : α) : Array α :=
|
def singleton (v : α) : Array α :=
|
||||||
mkArray 1 v
|
mkArray 1 v
|
||||||
|
|
||||||
|
/-- Low-level version of `size` that directly queries the C array object cached size.
|
||||||
|
While this is not provable, `usize` always returns the exact size of the array since
|
||||||
|
the implementation only supports arrays of size less than `USize.size`.
|
||||||
|
-/
|
||||||
|
@[extern "lean_array_size", simp]
|
||||||
|
def usize (a : @& Array α) : USize := a.size.toUSize
|
||||||
|
|
||||||
/-- Low-level version of `fget` which is as fast as a C array read.
|
/-- Low-level version of `fget` which is as fast as a C array read.
|
||||||
`Fin` values are represented as tag pointers in the Lean runtime. Thus,
|
`Fin` values are represented as tag pointers in the Lean runtime. Thus,
|
||||||
`fget` may be slightly slower than `uget`. -/
|
`fget` may be slightly slower than `uget`. -/
|
||||||
@@ -60,8 +67,6 @@ def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
|
|||||||
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
||||||
getElem xs i h := xs.uget i h
|
getElem xs i h := xs.uget i h
|
||||||
|
|
||||||
instance : LawfulGetElem (Array α) USize α fun xs i => i.toNat < xs.size where
|
|
||||||
|
|
||||||
def back [Inhabited α] (a : Array α) : α :=
|
def back [Inhabited α] (a : Array α) : α :=
|
||||||
a.get! (a.size - 1)
|
a.get! (a.size - 1)
|
||||||
|
|
||||||
@@ -103,7 +108,7 @@ def swap (a : Array α) (i j : @& Fin a.size) : Array α :=
|
|||||||
a'.set (size_set a i v₂ ▸ j) v₁
|
a'.set (size_set a i v₂ ▸ j) v₁
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Swaps two entries in an array, or panics if either index is out of bounds.
|
Swaps two entries in an array, or returns the array unchanged if either index is out of bounds.
|
||||||
|
|
||||||
This will perform the update destructively provided that `a` has a reference
|
This will perform the update destructively provided that `a` has a reference
|
||||||
count of 1 when called.
|
count of 1 when called.
|
||||||
@@ -176,7 +181,7 @@ def modifyOp (self : Array α) (idx : Nat) (f : α → α) : Array α :=
|
|||||||
|
|
||||||
This kind of low level trick can be removed with a little bit of compiler support. For example, if the compiler simplifies `as.size < usizeSz` to true. -/
|
This kind of low level trick can be removed with a little bit of compiler support. For example, if the compiler simplifies `as.size < usizeSz` to true. -/
|
||||||
@[inline] unsafe def forInUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : m β :=
|
@[inline] unsafe def forInUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : Array α) (b : β) (f : α → β → m (ForInStep β)) : m β :=
|
||||||
let sz := USize.ofNat as.size
|
let sz := as.usize
|
||||||
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
||||||
if i < sz then
|
if i < sz then
|
||||||
let a := as.uget i lcProof
|
let a := as.uget i lcProof
|
||||||
@@ -282,7 +287,7 @@ def foldrM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
|
|||||||
/-- See comment at `forInUnsafe` -/
|
/-- See comment at `forInUnsafe` -/
|
||||||
@[inline]
|
@[inline]
|
||||||
unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β) :=
|
unsafe def mapMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α → m β) (as : Array α) : m (Array β) :=
|
||||||
let sz := USize.ofNat as.size
|
let sz := as.usize
|
||||||
let rec @[specialize] map (i : USize) (r : Array NonScalar) : m (Array PNonScalar.{v}) := do
|
let rec @[specialize] map (i : USize) (r : Array NonScalar) : m (Array PNonScalar.{v}) := do
|
||||||
if i < sz then
|
if i < sz then
|
||||||
let v := r.uget i lcProof
|
let v := r.uget i lcProof
|
||||||
@@ -481,7 +486,7 @@ def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool
|
|||||||
Id.run <| as.allM p start stop
|
Id.run <| as.allM p start stop
|
||||||
|
|
||||||
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
def contains [BEq α] (as : Array α) (a : α) : Bool :=
|
||||||
as.any fun b => a == b
|
as.any (· == a)
|
||||||
|
|
||||||
def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
def elem [BEq α] (a : α) (as : Array α) : Bool :=
|
||||||
as.contains a
|
as.contains a
|
||||||
@@ -791,11 +796,11 @@ def toArrayLit (a : Array α) (n : Nat) (hsz : a.size = n) : Array α :=
|
|||||||
theorem ext' {as bs : Array α} (h : as.data = bs.data) : as = bs := by
|
theorem ext' {as bs : Array α} (h : as.data = bs.data) : as = bs := by
|
||||||
cases as; cases bs; simp at h; rw [h]
|
cases as; cases bs; simp at h; rw [h]
|
||||||
|
|
||||||
theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).data = acc.data ++ as := by
|
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).data = acc.data ++ as := by
|
||||||
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
|
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
|
||||||
|
|
||||||
theorem data_toArray (as : List α) : as.toArray.data = as := by
|
theorem data_toArray (as : List α) : as.toArray.data = as := by
|
||||||
simp [List.toArray, toArrayAux_eq, Array.mkEmpty]
|
simp [List.toArray, Array.mkEmpty]
|
||||||
|
|
||||||
theorem toArrayLit_eq (as : Array α) (n : Nat) (hsz : as.size = n) : as = toArrayLit as n hsz := by
|
theorem toArrayLit_eq (as : Array α) (n : Nat) (hsz : as.size = n) : as = toArrayLit as n hsz := by
|
||||||
apply ext'
|
apply ext'
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import Init.Data.Nat.Linear
|
|||||||
import Init.NotationExtra
|
import Init.NotationExtra
|
||||||
|
|
||||||
theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : as = bs ∧ a = b := by
|
theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : as = bs ∧ a = b := by
|
||||||
simp [push] at h
|
simp only [push, mk.injEq] at h
|
||||||
have ⟨h₁, h₂⟩ := List.of_concat_eq_concat h
|
have ⟨h₁, h₂⟩ := List.of_concat_eq_concat h
|
||||||
cases as; cases bs
|
cases as; cases bs
|
||||||
simp_all
|
simp_all
|
||||||
|
|||||||
@@ -27,17 +27,17 @@ decreasing_by decreasing_trivial_pre_omega
|
|||||||
theorem eq_of_isEqv [DecidableEq α] (a b : Array α) : Array.isEqv a b (fun x y => x = y) → a = b := by
|
theorem eq_of_isEqv [DecidableEq α] (a b : Array α) : Array.isEqv a b (fun x y => x = y) → a = b := by
|
||||||
simp [Array.isEqv]
|
simp [Array.isEqv]
|
||||||
split
|
split
|
||||||
case inr => intro; contradiction
|
next hsz =>
|
||||||
case inl hsz =>
|
|
||||||
intro h
|
intro h
|
||||||
have aux := eq_of_isEqvAux a b hsz 0 (Nat.zero_le ..) h
|
have aux := eq_of_isEqvAux a b hsz 0 (Nat.zero_le ..) h
|
||||||
exact ext a b hsz fun i h _ => aux i (Nat.zero_le ..) _
|
exact ext a b hsz fun i h _ => aux i (Nat.zero_le ..) _
|
||||||
|
next => intro; contradiction
|
||||||
|
|
||||||
theorem isEqvAux_self [DecidableEq α] (a : Array α) (i : Nat) : Array.isEqvAux a a rfl (fun x y => x = y) i = true := by
|
theorem isEqvAux_self [DecidableEq α] (a : Array α) (i : Nat) : Array.isEqvAux a a rfl (fun x y => x = y) i = true := by
|
||||||
unfold Array.isEqvAux
|
unfold Array.isEqvAux
|
||||||
split
|
split
|
||||||
case inl h => simp [h, isEqvAux_self a (i+1)]
|
next h => simp [h, isEqvAux_self a (i+1)]
|
||||||
case inr h => simp [h]
|
next h => simp [h]
|
||||||
termination_by a.size - i
|
termination_by a.size - i
|
||||||
decreasing_by decreasing_trivial_pre_omega
|
decreasing_by decreasing_trivial_pre_omega
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ Authors: Mario Carneiro
|
|||||||
prelude
|
prelude
|
||||||
import Init.Data.Nat.MinMax
|
import Init.Data.Nat.MinMax
|
||||||
import Init.Data.Nat.Lemmas
|
import Init.Data.Nat.Lemmas
|
||||||
import Init.Data.List.Lemmas
|
import Init.Data.List.Monadic
|
||||||
|
import Init.Data.List.Nat.Range
|
||||||
import Init.Data.Fin.Basic
|
import Init.Data.Fin.Basic
|
||||||
import Init.Data.Array.Mem
|
import Init.Data.Array.Mem
|
||||||
import Init.TacticsExtra
|
import Init.TacticsExtra
|
||||||
@@ -14,7 +15,7 @@ import Init.TacticsExtra
|
|||||||
/-!
|
/-!
|
||||||
## Bootstrapping theorems about arrays
|
## Bootstrapping theorems about arrays
|
||||||
|
|
||||||
This file contains some theorems about `Array` and `List` needed for `Std.List.Basic`.
|
This file contains some theorems about `Array` and `List` needed for `Init.Data.List.Impl`.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
namespace Array
|
namespace Array
|
||||||
@@ -34,9 +35,13 @@ attribute [simp] data_toArray uset
|
|||||||
|
|
||||||
@[simp] theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
|
@[simp] theorem size_mk (as : List α) : (Array.mk as).size = as.length := by simp [size]
|
||||||
|
|
||||||
theorem getElem_eq_data_get (a : Array α) (h : i < a.size) : a[i] = a.data.get ⟨i, h⟩ := by
|
theorem getElem_eq_data_getElem (a : Array α) (h : i < a.size) : a[i] = a.data[i] := by
|
||||||
by_cases i < a.size <;> (try simp [*]) <;> rfl
|
by_cases i < a.size <;> (try simp [*]) <;> rfl
|
||||||
|
|
||||||
|
@[deprecated getElem_eq_data_getElem (since := "2024-06-12")]
|
||||||
|
theorem getElem_eq_data_get (a : Array α) (h : i < a.size) : a[i] = a.data.get ⟨i, h⟩ := by
|
||||||
|
simp [getElem_eq_data_getElem]
|
||||||
|
|
||||||
theorem foldlM_eq_foldlM_data.aux [Monad m]
|
theorem foldlM_eq_foldlM_data.aux [Monad m]
|
||||||
(f : β → α → m β) (arr : Array α) (i j) (H : arr.size ≤ i + j) (b) :
|
(f : β → α → m β) (arr : Array α) (i j) (H : arr.size ≤ i + j) (b) :
|
||||||
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.data.drop j).foldlM f b := by
|
foldlM.loop f arr arr.size (Nat.le_refl _) i j b = (arr.data.drop j).foldlM f b := by
|
||||||
@@ -47,7 +52,7 @@ theorem foldlM_eq_foldlM_data.aux [Monad m]
|
|||||||
simp [foldlM_eq_foldlM_data.aux f arr i (j+1) H]
|
simp [foldlM_eq_foldlM_data.aux f arr i (j+1) H]
|
||||||
rw (config := {occs := .pos [2]}) [← List.get_drop_eq_drop _ _ ‹_›]
|
rw (config := {occs := .pos [2]}) [← List.get_drop_eq_drop _ _ ‹_›]
|
||||||
rfl
|
rfl
|
||||||
· rw [List.drop_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||||
|
|
||||||
theorem foldlM_eq_foldlM_data [Monad m]
|
theorem foldlM_eq_foldlM_data [Monad m]
|
||||||
(f : β → α → m β) (init : β) (arr : Array α) :
|
(f : β → α → m β) (init : β) (arr : Array α) :
|
||||||
@@ -114,11 +119,11 @@ theorem foldr_push (f : α → β → β) (init : β) (arr : Array α) (a : α)
|
|||||||
theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
||||||
have : i < (a.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt]
|
have : i < (a.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt]
|
||||||
(a.push x)[i] = a[i] := by
|
(a.push x)[i] = a[i] := by
|
||||||
simp only [push, getElem_eq_data_get, List.concat_eq_append, List.get_append_left, h]
|
simp only [push, getElem_eq_data_getElem, List.concat_eq_append, List.getElem_append_left, h]
|
||||||
|
|
||||||
@[simp] theorem get_push_eq (a : Array α) (x : α) : (a.push x)[a.size] = x := by
|
@[simp] theorem get_push_eq (a : Array α) (x : α) : (a.push x)[a.size] = x := by
|
||||||
simp only [push, getElem_eq_data_get, List.concat_eq_append]
|
simp only [push, getElem_eq_data_getElem, List.concat_eq_append]
|
||||||
rw [List.get_append_right] <;> simp [getElem_eq_data_get, Nat.zero_lt_one]
|
rw [List.getElem_append_right] <;> simp [getElem_eq_data_getElem, Nat.zero_lt_one]
|
||||||
|
|
||||||
theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
|
theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
|
||||||
(a.push x)[i] = if h : i < a.size then a[i] else x := by
|
(a.push x)[i] = if h : i < a.size then a[i] else x := by
|
||||||
@@ -135,8 +140,9 @@ where
|
|||||||
mapM.map f arr i r = (arr.data.drop i).foldlM (fun bs a => bs.push <$> f a) r := by
|
mapM.map f arr i r = (arr.data.drop i).foldlM (fun bs a => bs.push <$> f a) r := by
|
||||||
unfold mapM.map; split
|
unfold mapM.map; split
|
||||||
· rw [← List.get_drop_eq_drop _ i ‹_›]
|
· rw [← List.get_drop_eq_drop _ i ‹_›]
|
||||||
simp [aux (i+1), map_eq_pure_bind]; rfl
|
simp only [aux (i + 1), map_eq_pure_bind, data_length, List.foldlM_cons, bind_assoc, pure_bind]
|
||||||
· rw [List.drop_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
rfl
|
||||||
|
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||||
termination_by arr.size - i
|
termination_by arr.size - i
|
||||||
decreasing_by decreasing_trivial_pre_omega
|
decreasing_by decreasing_trivial_pre_omega
|
||||||
|
|
||||||
@@ -215,7 +221,7 @@ theorem getElem?_len_le (a : Array α) {i : Nat} (h : a.size ≤ i) : a[i]? = no
|
|||||||
theorem getD_get? (a : Array α) (i : Nat) (d : α) :
|
theorem getD_get? (a : Array α) (i : Nat) (d : α) :
|
||||||
Option.getD a[i]? d = if p : i < a.size then a[i]'p else d := by
|
Option.getD a[i]? d = if p : i < a.size then a[i]'p else d := by
|
||||||
if h : i < a.size then
|
if h : i < a.size then
|
||||||
simp [setD, h, getElem?]
|
simp [setD, h, getElem?_def]
|
||||||
else
|
else
|
||||||
have p : i ≥ a.size := Nat.le_of_not_gt h
|
have p : i ≥ a.size := Nat.le_of_not_gt h
|
||||||
simp [setD, getElem?_len_le _ p, h]
|
simp [setD, getElem?_len_le _ p, h]
|
||||||
@@ -233,11 +239,11 @@ theorem get!_eq_getD [Inhabited α] (a : Array α) : a.get! n = a.getD n default
|
|||||||
@[simp] theorem getElem_set_eq (a : Array α) (i : Fin a.size) (v : α) {j : Nat}
|
@[simp] theorem getElem_set_eq (a : Array α) (i : Fin a.size) (v : α) {j : Nat}
|
||||||
(eq : i.val = j) (p : j < (a.set i v).size) :
|
(eq : i.val = j) (p : j < (a.set i v).size) :
|
||||||
(a.set i v)[j]'p = v := by
|
(a.set i v)[j]'p = v := by
|
||||||
simp [set, getElem_eq_data_get, ←eq]
|
simp [set, getElem_eq_data_getElem, ←eq]
|
||||||
|
|
||||||
@[simp] theorem getElem_set_ne (a : Array α) (i : Fin a.size) (v : α) {j : Nat} (pj : j < (a.set i v).size)
|
@[simp] theorem getElem_set_ne (a : Array α) (i : Fin a.size) (v : α) {j : Nat} (pj : j < (a.set i v).size)
|
||||||
(h : i.val ≠ j) : (a.set i v)[j]'pj = a[j]'(size_set a i v ▸ pj) := by
|
(h : i.val ≠ j) : (a.set i v)[j]'pj = a[j]'(size_set a i v ▸ pj) := by
|
||||||
simp only [set, getElem_eq_data_get, List.get_set_ne _ h]
|
simp only [set, getElem_eq_data_getElem, List.getElem_set_ne h]
|
||||||
|
|
||||||
theorem getElem_set (a : Array α) (i : Fin a.size) (v : α) (j : Nat)
|
theorem getElem_set (a : Array α) (i : Fin a.size) (v : α) (j : Nat)
|
||||||
(h : j < (a.set i v).size) :
|
(h : j < (a.set i v).size) :
|
||||||
@@ -321,7 +327,7 @@ termination_by n - i
|
|||||||
@[simp] theorem mkArray_data (n : Nat) (v : α) : (mkArray n v).data = List.replicate n v := rfl
|
@[simp] theorem mkArray_data (n : Nat) (v : α) : (mkArray n v).data = List.replicate n v := rfl
|
||||||
|
|
||||||
@[simp] theorem getElem_mkArray (n : Nat) (v : α) (h : i < (mkArray n v).size) :
|
@[simp] theorem getElem_mkArray (n : Nat) (v : α) (h : i < (mkArray n v).size) :
|
||||||
(mkArray n v)[i] = v := by simp [Array.getElem_eq_data_get]
|
(mkArray n v)[i] = v := by simp [Array.getElem_eq_data_getElem]
|
||||||
|
|
||||||
/-- # mem -/
|
/-- # mem -/
|
||||||
|
|
||||||
@@ -329,10 +335,21 @@ theorem mem_data {a : α} {l : Array α} : a ∈ l.data ↔ a ∈ l := (mem_def
|
|||||||
|
|
||||||
theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
|
theorem not_mem_nil (a : α) : ¬ a ∈ #[] := nofun
|
||||||
|
|
||||||
|
theorem getElem_of_mem {a : α} {as : Array α} :
|
||||||
|
a ∈ as → (∃ (n : Nat) (h : n < as.size), as[n]'h = a) := by
|
||||||
|
intro ha
|
||||||
|
rcases List.getElem_of_mem ha.val with ⟨i, hbound, hi⟩
|
||||||
|
exists i
|
||||||
|
exists hbound
|
||||||
|
|
||||||
/-- # get lemmas -/
|
/-- # get lemmas -/
|
||||||
|
|
||||||
|
theorem lt_of_getElem {x : α} {a : Array α} {idx : Nat} {hidx : idx < a.size} (_ : a[idx] = x) :
|
||||||
|
idx < a.size :=
|
||||||
|
hidx
|
||||||
|
|
||||||
theorem getElem?_mem {l : Array α} {i : Fin l.size} : l[i] ∈ l := by
|
theorem getElem?_mem {l : Array α} {i : Fin l.size} : l[i] ∈ l := by
|
||||||
erw [Array.mem_def, getElem_eq_data_get]
|
erw [Array.mem_def, getElem_eq_data_getElem]
|
||||||
apply List.get_mem
|
apply List.get_mem
|
||||||
|
|
||||||
theorem getElem_fin_eq_data_get (a : Array α) (i : Fin _) : a[i] = a.data.get i := rfl
|
theorem getElem_fin_eq_data_get (a : Array α) (i : Fin _) : a[i] = a.data.get i := rfl
|
||||||
@@ -347,7 +364,7 @@ theorem get?_len_le (a : Array α) (i : Nat) (h : a.size ≤ i) : a[i]? = none :
|
|||||||
simp [getElem?_neg, h]
|
simp [getElem?_neg, h]
|
||||||
|
|
||||||
theorem getElem_mem_data (a : Array α) (h : i < a.size) : a[i] ∈ a.data := by
|
theorem getElem_mem_data (a : Array α) (h : i < a.size) : a[i] ∈ a.data := by
|
||||||
simp only [getElem_eq_data_get, List.get_mem]
|
simp only [getElem_eq_data_getElem, List.getElem_mem]
|
||||||
|
|
||||||
theorem getElem?_eq_data_get? (a : Array α) (i : Nat) : a[i]? = a.data.get? i := by
|
theorem getElem?_eq_data_get? (a : Array α) (i : Nat) : a[i]? = a.data.get? i := by
|
||||||
by_cases i < a.size <;> simp_all [getElem?_pos, getElem?_neg, List.get?_eq_get, eq_comm]; rfl
|
by_cases i < a.size <;> simp_all [getElem?_pos, getElem?_neg, List.get?_eq_get, eq_comm]; rfl
|
||||||
@@ -378,24 +395,24 @@ theorem get?_push {a : Array α} : (a.push x)[i]? = if i = a.size then some x el
|
|||||||
| Or.inl g =>
|
| Or.inl g =>
|
||||||
have h1 : i < a.size + 1 := by omega
|
have h1 : i < a.size + 1 := by omega
|
||||||
have h2 : i ≠ a.size := by omega
|
have h2 : i ≠ a.size := by omega
|
||||||
simp [getElem?, size_push, g, h1, h2, get_push_lt]
|
simp [getElem?_def, size_push, g, h1, h2, get_push_lt]
|
||||||
| Or.inr (Or.inl heq) =>
|
| Or.inr (Or.inl heq) =>
|
||||||
simp [heq, getElem?_pos, get_push_eq]
|
simp [heq, getElem?_pos, get_push_eq]
|
||||||
| Or.inr (Or.inr g) =>
|
| Or.inr (Or.inr g) =>
|
||||||
simp only [getElem?, size_push]
|
simp only [getElem?_def, size_push]
|
||||||
have h1 : ¬ (i < a.size) := by omega
|
have h1 : ¬ (i < a.size) := by omega
|
||||||
have h2 : ¬ (i < a.size + 1) := by omega
|
have h2 : ¬ (i < a.size + 1) := by omega
|
||||||
have h3 : i ≠ a.size := by omega
|
have h3 : i ≠ a.size := by omega
|
||||||
simp [h1, h2, h3]
|
simp [h1, h2, h3]
|
||||||
|
|
||||||
@[simp] theorem get?_size {a : Array α} : a[a.size]? = none := by
|
@[simp] theorem get?_size {a : Array α} : a[a.size]? = none := by
|
||||||
simp only [getElem?, Nat.lt_irrefl, dite_false]
|
simp only [getElem?_def, Nat.lt_irrefl, dite_false]
|
||||||
|
|
||||||
@[simp] theorem data_set (a : Array α) (i v) : (a.set i v).data = a.data.set i.1 v := rfl
|
@[simp] theorem data_set (a : Array α) (i v) : (a.set i v).data = a.data.set i.1 v := rfl
|
||||||
|
|
||||||
theorem get_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
theorem get_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
||||||
(a.set i v)[i.1] = v := by
|
(a.set i v)[i.1] = v := by
|
||||||
simp only [set, getElem_eq_data_get, List.get_set_eq]
|
simp only [set, getElem_eq_data_getElem, List.getElem_set_eq]
|
||||||
|
|
||||||
theorem get?_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
theorem get?_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
||||||
(a.set i v)[i.1]? = v := by simp [getElem?_pos, i.2]
|
(a.set i v)[i.1]? = v := by simp [getElem?_pos, i.2]
|
||||||
@@ -414,7 +431,7 @@ theorem get_set (a : Array α) (i : Fin a.size) (j : Nat) (hj : j < a.size) (v :
|
|||||||
|
|
||||||
@[simp] theorem get_set_ne (a : Array α) (i : Fin a.size) {j : Nat} (v : α) (hj : j < a.size)
|
@[simp] theorem get_set_ne (a : Array α) (i : Fin a.size) {j : Nat} (v : α) (hj : j < a.size)
|
||||||
(h : i.1 ≠ j) : (a.set i v)[j]'(by simp [*]) = a[j] := by
|
(h : i.1 ≠ j) : (a.set i v)[j]'(by simp [*]) = a[j] := by
|
||||||
simp only [set, getElem_eq_data_get, List.get_set_ne _ h]
|
simp only [set, getElem_eq_data_getElem, List.getElem_set_ne h]
|
||||||
|
|
||||||
theorem getElem_setD (a : Array α) (i : Nat) (v : α) (h : i < (setD a i v).size) :
|
theorem getElem_setD (a : Array α) (i : Nat) (v : α) (h : i < (setD a i v).size) :
|
||||||
(setD a i v)[i] = v := by
|
(setD a i v)[i] = v := by
|
||||||
@@ -452,7 +469,7 @@ theorem swapAt!_def (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
|
|||||||
|
|
||||||
@[simp] theorem getElem_pop (a : Array α) (i : Nat) (hi : i < a.pop.size) :
|
@[simp] theorem getElem_pop (a : Array α) (i : Nat) (hi : i < a.pop.size) :
|
||||||
a.pop[i] = a[i]'(Nat.lt_of_lt_of_le (a.size_pop ▸ hi) (Nat.sub_le _ _)) :=
|
a.pop[i] = a[i]'(Nat.lt_of_lt_of_le (a.size_pop ▸ hi) (Nat.sub_le _ _)) :=
|
||||||
List.get_dropLast ..
|
List.getElem_dropLast ..
|
||||||
|
|
||||||
theorem eq_empty_of_size_eq_zero {as : Array α} (h : as.size = 0) : as = #[] := by
|
theorem eq_empty_of_size_eq_zero {as : Array α} (h : as.size = 0) : as = #[] := by
|
||||||
apply ext
|
apply ext
|
||||||
@@ -500,27 +517,35 @@ theorem size_eq_length_data (as : Array α) : as.size = as.data.length := rfl
|
|||||||
simp only [mkEmpty_eq, size_push] at *
|
simp only [mkEmpty_eq, size_push] at *
|
||||||
omega
|
omega
|
||||||
|
|
||||||
|
@[simp] theorem data_range (n : Nat) : (range n).data = List.range n := by
|
||||||
|
induction n <;> simp_all [range, Nat.fold, flip, List.range_succ]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem getElem_range {n : Nat} {x : Nat} (h : x < (Array.range n).size) : (Array.range n)[x] = x := by
|
||||||
|
simp [getElem_eq_data_getElem]
|
||||||
|
|
||||||
|
set_option linter.deprecated false in
|
||||||
@[simp] theorem reverse_data (a : Array α) : a.reverse.data = a.data.reverse := by
|
@[simp] theorem reverse_data (a : Array α) : a.reverse.data = a.data.reverse := by
|
||||||
let rec go (as : Array α) (i j hj)
|
let rec go (as : Array α) (i j hj)
|
||||||
(h : i + j + 1 = a.size) (h₂ : as.size = a.size)
|
(h : i + j + 1 = a.size) (h₂ : as.size = a.size)
|
||||||
(H : ∀ k, as.data.get? k = if i ≤ k ∧ k ≤ j then a.data.get? k else a.data.reverse.get? k)
|
(H : ∀ k, as.data.get? k = if i ≤ k ∧ k ≤ j then a.data.get? k else a.data.reverse.get? k)
|
||||||
(k) : (reverse.loop as i ⟨j, hj⟩).data.get? k = a.data.reverse.get? k := by
|
(k) : (reverse.loop as i ⟨j, hj⟩).data.get? k = a.data.reverse.get? k := by
|
||||||
rw [reverse.loop]; dsimp; split <;> rename_i h₁
|
rw [reverse.loop]; dsimp; split <;> rename_i h₁
|
||||||
· have := reverse.termination h₁
|
· have p := reverse.termination h₁
|
||||||
match j with | j+1 => ?_
|
match j with | j+1 => ?_
|
||||||
simp at *
|
simp only [Nat.add_sub_cancel] at p ⊢
|
||||||
rw [(go · (i+1) j)]
|
rw [(go · (i+1) j)]
|
||||||
· rwa [Nat.add_right_comm i]
|
· rwa [Nat.add_right_comm i]
|
||||||
· simp [size_swap, h₂]
|
· simp [size_swap, h₂]
|
||||||
· intro k
|
· intro k
|
||||||
rw [← getElem?_eq_data_get?, get?_swap]
|
rw [← getElem?_eq_data_get?, get?_swap]
|
||||||
simp [getElem?_eq_data_get?, getElem_eq_data_get, ← List.get?_eq_get, H, Nat.le_of_lt h₁]
|
simp only [H, getElem_eq_data_get, ← List.get?_eq_get, Nat.le_of_lt h₁, getElem?_eq_data_get?]
|
||||||
split <;> rename_i h₂
|
split <;> rename_i h₂
|
||||||
· simp [← h₂, Nat.not_le.2 (Nat.lt_succ_self _)]
|
· simp only [← h₂, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, and_false]
|
||||||
exact (List.get?_reverse' _ _ (Eq.trans (by simp_arith) h)).symm
|
exact (List.get?_reverse' (j+1) i (Eq.trans (by simp_arith) h)).symm
|
||||||
split <;> rename_i h₃
|
split <;> rename_i h₃
|
||||||
· simp [← h₃, Nat.not_le.2 (Nat.lt_succ_self _)]
|
· simp only [← h₃, Nat.not_le.2 (Nat.lt_succ_self _), Nat.le_refl, false_and]
|
||||||
exact (List.get?_reverse' _ _ (Eq.trans (by simp_arith) h)).symm
|
exact (List.get?_reverse' i (j+1) (Eq.trans (by simp_arith) h)).symm
|
||||||
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
|
simp only [Nat.succ_le, Nat.lt_iff_le_and_ne.trans (and_iff_left h₃),
|
||||||
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
|
Nat.lt_succ.symm.trans (Nat.lt_iff_le_and_ne.trans (and_iff_left (Ne.symm h₂)))]
|
||||||
· rw [H]; split <;> rename_i h₂
|
· rw [H]; split <;> rename_i h₂
|
||||||
@@ -529,13 +554,17 @@ theorem size_eq_length_data (as : Array α) : as.size = as.data.length := rfl
|
|||||||
exact (List.get?_reverse' _ _ h).symm
|
exact (List.get?_reverse' _ _ h).symm
|
||||||
· rfl
|
· rfl
|
||||||
termination_by j - i
|
termination_by j - i
|
||||||
simp only [reverse]; split
|
simp only [reverse]
|
||||||
|
split
|
||||||
· match a with | ⟨[]⟩ | ⟨[_]⟩ => rfl
|
· match a with | ⟨[]⟩ | ⟨[_]⟩ => rfl
|
||||||
· have := Nat.sub_add_cancel (Nat.le_of_not_le ‹_›)
|
· have := Nat.sub_add_cancel (Nat.le_of_not_le ‹_›)
|
||||||
refine List.ext <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
|
refine List.ext_get? <| go _ _ _ _ (by simp [this]) rfl fun k => ?_
|
||||||
split; {rfl}; rename_i h
|
split
|
||||||
simp [← show k < _ + 1 ↔ _ from Nat.lt_succ (n := a.size - 1), this] at h
|
· rfl
|
||||||
rw [List.get?_eq_none.2 ‹_›, List.get?_eq_none.2 (a.data.length_reverse ▸ ‹_›)]
|
· rename_i h
|
||||||
|
simp only [← show k < _ + 1 ↔ _ from Nat.lt_succ (n := a.size - 1), this, Nat.zero_le,
|
||||||
|
true_and, Nat.not_lt] at h
|
||||||
|
rw [List.get?_eq_none.2 ‹_›, List.get?_eq_none.2 (a.data.length_reverse ▸ ‹_›)]
|
||||||
|
|
||||||
/-! ### foldl / foldr -/
|
/-! ### foldl / foldr -/
|
||||||
|
|
||||||
@@ -697,12 +726,27 @@ theorem mapIdx_spec (as : Array α) (f : Fin as.size → α → β)
|
|||||||
unfold modify modifyM Id.run
|
unfold modify modifyM Id.run
|
||||||
split <;> simp
|
split <;> simp
|
||||||
|
|
||||||
|
theorem getElem_modify {as : Array α} {x i} (h : i < as.size) :
|
||||||
|
(as.modify x f)[i]'(by simp [h]) = if x = i then f as[i] else as[i] := by
|
||||||
|
simp only [modify, modifyM, get_eq_getElem, Id.run, Id.pure_eq]
|
||||||
|
split
|
||||||
|
· simp only [Id.bind_eq, get_set _ _ _ h]; split <;> simp [*]
|
||||||
|
· rw [if_neg (mt (by rintro rfl; exact h) ‹_›)]
|
||||||
|
|
||||||
|
theorem getElem_modify_self {as : Array α} {i : Nat} (h : i < as.size) (f : α → α) :
|
||||||
|
(as.modify i f)[i]'(by simp [h]) = f as[i] := by
|
||||||
|
simp [getElem_modify h]
|
||||||
|
|
||||||
|
theorem getElem_modify_of_ne {as : Array α} {i : Nat} (hj : j < as.size)
|
||||||
|
(f : α → α) (h : i ≠ j) :
|
||||||
|
(as.modify i f)[j]'(by rwa [size_modify]) = as[j] := by
|
||||||
|
simp [getElem_modify hj, h]
|
||||||
|
|
||||||
|
@[deprecated getElem_modify (since := "2024-08-08")]
|
||||||
theorem get_modify {arr : Array α} {x i} (h : i < arr.size) :
|
theorem get_modify {arr : Array α} {x i} (h : i < arr.size) :
|
||||||
(arr.modify x f).get ⟨i, by simp [h]⟩ =
|
(arr.modify x f).get ⟨i, by simp [h]⟩ =
|
||||||
if x = i then f (arr.get ⟨i, h⟩) else arr.get ⟨i, h⟩ := by
|
if x = i then f (arr.get ⟨i, h⟩) else arr.get ⟨i, h⟩ := by
|
||||||
simp [modify, modifyM, Id.run]; split
|
simp [getElem_modify h]
|
||||||
· simp [get_set _ _ _ h]; split <;> simp [*]
|
|
||||||
· rw [if_neg (mt (by rintro rfl; exact h) ‹_›)]
|
|
||||||
|
|
||||||
/-! ### filter -/
|
/-! ### filter -/
|
||||||
|
|
||||||
@@ -740,7 +784,7 @@ theorem mem_of_mem_filter {a : α} {l} (h : a ∈ filter p l) : a ∈ l :=
|
|||||||
exact this #[]
|
exact this #[]
|
||||||
induction l
|
induction l
|
||||||
· simp_all [Id.run]
|
· simp_all [Id.run]
|
||||||
· simp_all [Id.run]
|
· simp_all [Id.run, List.filterMap_cons]
|
||||||
split <;> simp_all
|
split <;> simp_all
|
||||||
|
|
||||||
@[simp] theorem mem_filterMap (f : α → Option β) (l : Array α) {b : β} :
|
@[simp] theorem mem_filterMap (f : α → Option β) (l : Array α) {b : β} :
|
||||||
@@ -765,17 +809,17 @@ theorem size_append (as bs : Array α) : (as ++ bs).size = as.size + bs.size :=
|
|||||||
|
|
||||||
theorem get_append_left {as bs : Array α} {h : i < (as ++ bs).size} (hlt : i < as.size) :
|
theorem get_append_left {as bs : Array α} {h : i < (as ++ bs).size} (hlt : i < as.size) :
|
||||||
(as ++ bs)[i] = as[i] := by
|
(as ++ bs)[i] = as[i] := by
|
||||||
simp only [getElem_eq_data_get]
|
simp only [getElem_eq_data_getElem]
|
||||||
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
||||||
conv => rhs; rw [← List.get_append_left (bs:=bs.data) (h':=h')]
|
conv => rhs; rw [← List.getElem_append_left (bs := bs.data) (h' := h')]
|
||||||
apply List.get_of_eq; rw [append_data]
|
apply List.get_of_eq; rw [append_data]
|
||||||
|
|
||||||
theorem get_append_right {as bs : Array α} {h : i < (as ++ bs).size} (hle : as.size ≤ i)
|
theorem get_append_right {as bs : Array α} {h : i < (as ++ bs).size} (hle : as.size ≤ i)
|
||||||
(hlt : i - as.size < bs.size := Nat.sub_lt_left_of_lt_add hle (size_append .. ▸ h)) :
|
(hlt : i - as.size < bs.size := Nat.sub_lt_left_of_lt_add hle (size_append .. ▸ h)) :
|
||||||
(as ++ bs)[i] = bs[i - as.size] := by
|
(as ++ bs)[i] = bs[i - as.size] := by
|
||||||
simp only [getElem_eq_data_get]
|
simp only [getElem_eq_data_getElem]
|
||||||
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
have h' : i < (as.data ++ bs.data).length := by rwa [← data_length, append_data] at h
|
||||||
conv => rhs; rw [← List.get_append_right (h':=h') (h:=Nat.not_lt_of_ge hle)]
|
conv => rhs; rw [← List.getElem_append_right (h' := h') (h := Nat.not_lt_of_ge hle)]
|
||||||
apply List.get_of_eq; rw [append_data]
|
apply List.get_of_eq; rw [append_data]
|
||||||
|
|
||||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||||
@@ -983,13 +1027,13 @@ theorem all_eq_true (p : α → Bool) (as : Array α) : all as p ↔ ∀ i : Fin
|
|||||||
simp [all_iff_forall, Fin.isLt]
|
simp [all_iff_forall, Fin.isLt]
|
||||||
|
|
||||||
theorem all_def {p : α → Bool} (as : Array α) : as.all p = as.data.all p := by
|
theorem all_def {p : α → Bool} (as : Array α) : as.all p = as.data.all p := by
|
||||||
rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]; simp only [List.mem_iff_get]
|
rw [Bool.eq_iff_iff, all_eq_true, List.all_eq_true]; simp only [List.mem_iff_getElem]
|
||||||
constructor
|
constructor
|
||||||
· rintro w x ⟨r, rfl⟩
|
· rintro w x ⟨r, h, rfl⟩
|
||||||
rw [← getElem_eq_data_get]
|
rw [← getElem_eq_data_getElem]
|
||||||
apply w
|
exact w ⟨r, h⟩
|
||||||
· intro w i
|
· intro w i
|
||||||
exact w as[i] ⟨i, (getElem_eq_data_get as i.2).symm⟩
|
exact w as[i] ⟨i, i.2, (getElem_eq_data_getElem as i.2).symm⟩
|
||||||
|
|
||||||
theorem all_eq_true_iff_forall_mem {l : Array α} : l.all p ↔ ∀ x, x ∈ l → p x := by
|
theorem all_eq_true_iff_forall_mem {l : Array α} : l.all p ↔ ∀ x, x ∈ l → p x := by
|
||||||
simp only [all_def, List.all_eq_true, mem_def]
|
simp only [all_def, List.all_eq_true, mem_def]
|
||||||
|
|||||||
@@ -13,17 +13,17 @@ namespace Array
|
|||||||
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
|
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
|
||||||
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
-- NB: This is defined as a structure rather than a plain def so that a lemma
|
||||||
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
-- like `sizeOf_lt_of_mem` will not apply with no actual arrays around.
|
||||||
structure Mem (a : α) (as : Array α) : Prop where
|
structure Mem (as : Array α) (a : α) : Prop where
|
||||||
val : a ∈ as.data
|
val : a ∈ as.data
|
||||||
|
|
||||||
instance : Membership α (Array α) where
|
instance : Membership α (Array α) where
|
||||||
mem a as := Mem a as
|
mem := Mem
|
||||||
|
|
||||||
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a < sizeOf as := by
|
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a < sizeOf as := by
|
||||||
cases as with | _ as =>
|
cases as with | _ as =>
|
||||||
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp_arith)
|
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp_arith)
|
||||||
|
|
||||||
@[simp] theorem sizeOf_get [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
|
theorem sizeOf_get [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
|
||||||
cases as with | _ as =>
|
cases as with | _ as =>
|
||||||
exact Nat.lt_trans (List.sizeOf_get ..) (by simp_arith)
|
exact Nat.lt_trans (List.sizeOf_get ..) (by simp_arith)
|
||||||
|
|
||||||
@@ -38,8 +38,8 @@ macro "array_get_dec" : tactic =>
|
|||||||
-- subsumed by simp
|
-- subsumed by simp
|
||||||
-- | with_reducible apply sizeOf_get
|
-- | with_reducible apply sizeOf_get
|
||||||
-- | with_reducible apply sizeOf_getElem
|
-- | with_reducible apply sizeOf_getElem
|
||||||
| (with_reducible apply Nat.lt_trans (sizeOf_get ..)); simp_arith
|
| (with_reducible apply Nat.lt_of_lt_of_le (sizeOf_get ..)); simp_arith
|
||||||
| (with_reducible apply Nat.lt_trans (sizeOf_getElem ..)); simp_arith
|
| (with_reducible apply Nat.lt_of_lt_of_le (sizeOf_getElem ..)); simp_arith
|
||||||
)
|
)
|
||||||
|
|
||||||
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_get_dec)
|
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_get_dec)
|
||||||
@@ -52,7 +52,7 @@ macro "array_mem_dec" : tactic =>
|
|||||||
`(tactic| first
|
`(tactic| first
|
||||||
| with_reducible apply Array.sizeOf_lt_of_mem; assumption; done
|
| with_reducible apply Array.sizeOf_lt_of_mem; assumption; done
|
||||||
| with_reducible
|
| with_reducible
|
||||||
apply Nat.lt_trans (Array.sizeOf_lt_of_mem ?h)
|
apply Nat.lt_of_lt_of_le (Array.sizeOf_lt_of_mem ?h)
|
||||||
case' h => assumption
|
case' h => assumption
|
||||||
simp_arith)
|
simp_arith)
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ def get (s : Subarray α) (i : Fin s.size) : α :=
|
|||||||
instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
||||||
getElem xs i h := xs.get ⟨i, h⟩
|
getElem xs i h := xs.get ⟨i, h⟩
|
||||||
|
|
||||||
instance : LawfulGetElem (Subarray α) Nat α fun xs i => i < xs.size where
|
|
||||||
|
|
||||||
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
|
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
|
||||||
if h : i < s.size then s.get ⟨i, h⟩ else v₀
|
if h : i < s.size then s.get ⟨i, h⟩ else v₀
|
||||||
|
|
||||||
|
|||||||
17
src/Init/Data/Array/TakeDrop.lean
Normal file
17
src/Init/Data/Array/TakeDrop.lean
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Markus Himmel
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.Array.Lemmas
|
||||||
|
import Init.Data.List.Nat.TakeDrop
|
||||||
|
|
||||||
|
namespace Array
|
||||||
|
|
||||||
|
theorem exists_of_uset (self : Array α) (i d h) :
|
||||||
|
∃ l₁ l₂, self.data = l₁ ++ self[i] :: l₂ ∧ List.length l₁ = i.toNat ∧
|
||||||
|
(self.uset i d h).data = l₁ ++ d :: l₂ := by
|
||||||
|
simpa [Array.getElem_eq_data_getElem] using List.exists_of_set _
|
||||||
|
|
||||||
|
end Array
|
||||||
60
src/Init/Data/BEq.lean
Normal file
60
src/Init/Data/BEq.lean
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Mario Carneiro, Markus Himmel
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.Bool
|
||||||
|
|
||||||
|
set_option linter.missingDocs true
|
||||||
|
|
||||||
|
/-- `PartialEquivBEq α` says that the `BEq` implementation is a
|
||||||
|
partial equivalence relation, that is:
|
||||||
|
* it is symmetric: `a == b → b == a`
|
||||||
|
* it is transitive: `a == b → b == c → a == c`.
|
||||||
|
-/
|
||||||
|
class PartialEquivBEq (α) [BEq α] : Prop where
|
||||||
|
/-- Symmetry for `BEq`. If `a == b` then `b == a`. -/
|
||||||
|
symm : (a : α) == b → b == a
|
||||||
|
/-- Transitivity for `BEq`. If `a == b` and `b == c` then `a == c`. -/
|
||||||
|
trans : (a : α) == b → b == c → a == c
|
||||||
|
|
||||||
|
/-- `ReflBEq α` says that the `BEq` implementation is reflexive. -/
|
||||||
|
class ReflBEq (α) [BEq α] : Prop where
|
||||||
|
/-- Reflexivity for `BEq`. -/
|
||||||
|
refl : (a : α) == a
|
||||||
|
|
||||||
|
/-- `EquivBEq` says that the `BEq` implementation is an equivalence relation. -/
|
||||||
|
class EquivBEq (α) [BEq α] extends PartialEquivBEq α, ReflBEq α : Prop
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem BEq.refl [BEq α] [ReflBEq α] {a : α} : a == a :=
|
||||||
|
ReflBEq.refl
|
||||||
|
|
||||||
|
theorem beq_of_eq [BEq α] [ReflBEq α] {a b : α} : a = b → a == b
|
||||||
|
| rfl => BEq.refl
|
||||||
|
|
||||||
|
theorem BEq.symm [BEq α] [PartialEquivBEq α] {a b : α} : a == b → b == a :=
|
||||||
|
PartialEquivBEq.symm
|
||||||
|
|
||||||
|
theorem BEq.comm [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = (b == a) :=
|
||||||
|
Bool.eq_iff_iff.2 ⟨BEq.symm, BEq.symm⟩
|
||||||
|
|
||||||
|
theorem BEq.symm_false [BEq α] [PartialEquivBEq α] {a b : α} : (a == b) = false → (b == a) = false :=
|
||||||
|
BEq.comm (α := α) ▸ id
|
||||||
|
|
||||||
|
theorem BEq.trans [BEq α] [PartialEquivBEq α] {a b c : α} : a == b → b == c → a == c :=
|
||||||
|
PartialEquivBEq.trans
|
||||||
|
|
||||||
|
theorem BEq.neq_of_neq_of_beq [BEq α] [PartialEquivBEq α] {a b c : α} :
|
||||||
|
(a == b) = false → b == c → (a == c) = false :=
|
||||||
|
fun h₁ h₂ => Bool.eq_false_iff.2 fun h₃ => Bool.eq_false_iff.1 h₁ (BEq.trans h₃ (BEq.symm h₂))
|
||||||
|
|
||||||
|
theorem BEq.neq_of_beq_of_neq [BEq α] [PartialEquivBEq α] {a b c : α} :
|
||||||
|
a == b → (b == c) = false → (a == c) = false :=
|
||||||
|
fun h₁ h₂ => Bool.eq_false_iff.2 fun h₃ => Bool.eq_false_iff.1 h₂ (BEq.trans (BEq.symm h₁) h₃)
|
||||||
|
|
||||||
|
instance (priority := low) [BEq α] [LawfulBEq α] : EquivBEq α where
|
||||||
|
refl := LawfulBEq.rfl
|
||||||
|
symm h := (beq_iff_eq _ _).2 <| Eq.symm <| (beq_iff_eq _ _).1 h
|
||||||
|
trans hab hbc := (beq_iff_eq _ _).2 <| ((beq_iff_eq _ _).1 hab).trans <| (beq_iff_eq _ _).1 hbc
|
||||||
@@ -20,6 +20,8 @@ We define many of the bitvector operations from the
|
|||||||
of SMT-LIBv2.
|
of SMT-LIBv2.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
|
set_option linter.missingDocs true
|
||||||
|
|
||||||
/--
|
/--
|
||||||
A bitvector of the specified width.
|
A bitvector of the specified width.
|
||||||
|
|
||||||
@@ -34,14 +36,14 @@ structure BitVec (w : Nat) where
|
|||||||
O(1), because we use `Fin` as the internal representation of a bitvector. -/
|
O(1), because we use `Fin` as the internal representation of a bitvector. -/
|
||||||
toFin : Fin (2^w)
|
toFin : Fin (2^w)
|
||||||
|
|
||||||
@[deprecated (since := "2024-04-12")]
|
/--
|
||||||
protected abbrev Std.BitVec := _root_.BitVec
|
Bitvectors have decidable equality. This should be used via the instance `DecidableEq (BitVec n)`.
|
||||||
|
-/
|
||||||
-- We manually derive the `DecidableEq` instances for `BitVec` because
|
-- We manually derive the `DecidableEq` instances for `BitVec` because
|
||||||
-- we want to have builtin support for bit-vector literals, and we
|
-- we want to have builtin support for bit-vector literals, and we
|
||||||
-- need a name for this function to implement `canUnfoldAtMatcher` at `WHNF.lean`.
|
-- need a name for this function to implement `canUnfoldAtMatcher` at `WHNF.lean`.
|
||||||
def BitVec.decEq (a b : BitVec n) : Decidable (a = b) :=
|
def BitVec.decEq (x y : BitVec n) : Decidable (x = y) :=
|
||||||
match a, b with
|
match x, y with
|
||||||
| ⟨n⟩, ⟨m⟩ =>
|
| ⟨n⟩, ⟨m⟩ =>
|
||||||
if h : n = m then
|
if h : n = m then
|
||||||
isTrue (h ▸ rfl)
|
isTrue (h ▸ rfl)
|
||||||
@@ -67,9 +69,9 @@ protected def ofNat (n : Nat) (i : Nat) : BitVec n where
|
|||||||
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
|
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
|
||||||
instance natCastInst : NatCast (BitVec w) := ⟨BitVec.ofNat w⟩
|
instance natCastInst : NatCast (BitVec w) := ⟨BitVec.ofNat w⟩
|
||||||
|
|
||||||
/-- Given a bitvector `a`, return the underlying `Nat`. This is O(1) because `BitVec` is a
|
/-- Given a bitvector `x`, return the underlying `Nat`. This is O(1) because `BitVec` is a
|
||||||
(zero-cost) wrapper around a `Nat`. -/
|
(zero-cost) wrapper around a `Nat`. -/
|
||||||
protected def toNat (a : BitVec n) : Nat := a.toFin.val
|
protected def toNat (x : BitVec n) : Nat := x.toFin.val
|
||||||
|
|
||||||
/-- Return the bound in terms of toNat. -/
|
/-- Return the bound in terms of toNat. -/
|
||||||
theorem isLt (x : BitVec w) : x.toNat < 2^w := x.toFin.isLt
|
theorem isLt (x : BitVec w) : x.toNat < 2^w := x.toFin.isLt
|
||||||
@@ -121,18 +123,18 @@ section getXsb
|
|||||||
@[inline] def getMsb (x : BitVec w) (i : Nat) : Bool := i < w && getLsb x (w-1-i)
|
@[inline] def getMsb (x : BitVec w) (i : Nat) : Bool := i < w && getLsb x (w-1-i)
|
||||||
|
|
||||||
/-- Return most-significant bit in bitvector. -/
|
/-- Return most-significant bit in bitvector. -/
|
||||||
@[inline] protected def msb (a : BitVec n) : Bool := getMsb a 0
|
@[inline] protected def msb (x : BitVec n) : Bool := getMsb x 0
|
||||||
|
|
||||||
end getXsb
|
end getXsb
|
||||||
|
|
||||||
section Int
|
section Int
|
||||||
|
|
||||||
/-- Interpret the bitvector as an integer stored in two's complement form. -/
|
/-- Interpret the bitvector as an integer stored in two's complement form. -/
|
||||||
protected def toInt (a : BitVec n) : Int :=
|
protected def toInt (x : BitVec n) : Int :=
|
||||||
if 2 * a.toNat < 2^n then
|
if 2 * x.toNat < 2^n then
|
||||||
a.toNat
|
x.toNat
|
||||||
else
|
else
|
||||||
(a.toNat : Int) - (2^n : Nat)
|
(x.toNat : Int) - (2^n : Nat)
|
||||||
|
|
||||||
/-- The `BitVec` with value `(2^n + (i mod 2^n)) mod 2^n`. -/
|
/-- The `BitVec` with value `(2^n + (i mod 2^n)) mod 2^n`. -/
|
||||||
protected def ofInt (n : Nat) (i : Int) : BitVec n := .ofNatLt (i % (Int.ofNat (2^n))).toNat (by
|
protected def ofInt (n : Nat) (i : Int) : BitVec n := .ofNatLt (i % (Int.ofNat (2^n))).toNat (by
|
||||||
@@ -151,12 +153,12 @@ end Int
|
|||||||
section Syntax
|
section Syntax
|
||||||
|
|
||||||
/-- Notation for bit vector literals. `i#n` is a shorthand for `BitVec.ofNat n i`. -/
|
/-- Notation for bit vector literals. `i#n` is a shorthand for `BitVec.ofNat n i`. -/
|
||||||
scoped syntax:max term:max noWs "#" noWs term:max : term
|
syntax:max num noWs "#" noWs term:max : term
|
||||||
macro_rules | `($i#$n) => `(BitVec.ofNat $n $i)
|
macro_rules | `($i:num#$n) => `(BitVec.ofNat $n $i)
|
||||||
|
|
||||||
/-- Unexpander for bit vector literals. -/
|
/-- Unexpander for bit vector literals. -/
|
||||||
@[app_unexpander BitVec.ofNat] def unexpandBitVecOfNat : Lean.PrettyPrinter.Unexpander
|
@[app_unexpander BitVec.ofNat] def unexpandBitVecOfNat : Lean.PrettyPrinter.Unexpander
|
||||||
| `($(_) $n $i) => `($i#$n)
|
| `($(_) $n $i:num) => `($i:num#$n)
|
||||||
| _ => throw ()
|
| _ => throw ()
|
||||||
|
|
||||||
/-- Notation for bit vector literals without truncation. `i#'lt` is a shorthand for `BitVec.ofNatLt i lt`. -/
|
/-- Notation for bit vector literals without truncation. `i#'lt` is a shorthand for `BitVec.ofNatLt i lt`. -/
|
||||||
@@ -198,7 +200,7 @@ instance : Add (BitVec n) := ⟨BitVec.add⟩
|
|||||||
Subtraction for bit vectors. This can be interpreted as either signed or unsigned subtraction
|
Subtraction for bit vectors. This can be interpreted as either signed or unsigned subtraction
|
||||||
modulo `2^n`.
|
modulo `2^n`.
|
||||||
-/
|
-/
|
||||||
protected def sub (x y : BitVec n) : BitVec n := .ofNat n (x.toNat + (2^n - y.toNat))
|
protected def sub (x y : BitVec n) : BitVec n := .ofNat n ((2^n - y.toNat) + x.toNat)
|
||||||
instance : Sub (BitVec n) := ⟨BitVec.sub⟩
|
instance : Sub (BitVec n) := ⟨BitVec.sub⟩
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -213,7 +215,7 @@ instance : Neg (BitVec n) := ⟨.neg⟩
|
|||||||
/--
|
/--
|
||||||
Return the absolute value of a signed bitvector.
|
Return the absolute value of a signed bitvector.
|
||||||
-/
|
-/
|
||||||
protected def abs (s : BitVec n) : BitVec n := if s.msb then .neg s else s
|
protected def abs (x : BitVec n) : BitVec n := if x.msb then .neg x else x
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Multiplication for bit vectors. This can be interpreted as either signed or unsigned negation
|
Multiplication for bit vectors. This can be interpreted as either signed or unsigned negation
|
||||||
@@ -260,12 +262,12 @@ sdiv 5#4 -2 = -2#4
|
|||||||
sdiv (-7#4) (-2) = 3#4
|
sdiv (-7#4) (-2) = 3#4
|
||||||
```
|
```
|
||||||
-/
|
-/
|
||||||
def sdiv (s t : BitVec n) : BitVec n :=
|
def sdiv (x y : BitVec n) : BitVec n :=
|
||||||
match s.msb, t.msb with
|
match x.msb, y.msb with
|
||||||
| false, false => udiv s t
|
| false, false => udiv x y
|
||||||
| false, true => .neg (udiv s (.neg t))
|
| false, true => .neg (udiv x (.neg y))
|
||||||
| true, false => .neg (udiv (.neg s) t)
|
| true, false => .neg (udiv (.neg x) y)
|
||||||
| true, true => udiv (.neg s) (.neg t)
|
| true, true => udiv (.neg x) (.neg y)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Signed division for bit vectors using SMTLIB rules for division by zero.
|
Signed division for bit vectors using SMTLIB rules for division by zero.
|
||||||
@@ -274,40 +276,40 @@ Specifically, `smtSDiv x 0 = if x >= 0 then -1 else 1`
|
|||||||
|
|
||||||
SMT-Lib name: `bvsdiv`.
|
SMT-Lib name: `bvsdiv`.
|
||||||
-/
|
-/
|
||||||
def smtSDiv (s t : BitVec n) : BitVec n :=
|
def smtSDiv (x y : BitVec n) : BitVec n :=
|
||||||
match s.msb, t.msb with
|
match x.msb, y.msb with
|
||||||
| false, false => smtUDiv s t
|
| false, false => smtUDiv x y
|
||||||
| false, true => .neg (smtUDiv s (.neg t))
|
| false, true => .neg (smtUDiv x (.neg y))
|
||||||
| true, false => .neg (smtUDiv (.neg s) t)
|
| true, false => .neg (smtUDiv (.neg x) y)
|
||||||
| true, true => smtUDiv (.neg s) (.neg t)
|
| true, true => smtUDiv (.neg x) (.neg y)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Remainder for signed division rounding to zero.
|
Remainder for signed division rounding to zero.
|
||||||
|
|
||||||
SMT_Lib name: `bvsrem`.
|
SMT_Lib name: `bvsrem`.
|
||||||
-/
|
-/
|
||||||
def srem (s t : BitVec n) : BitVec n :=
|
def srem (x y : BitVec n) : BitVec n :=
|
||||||
match s.msb, t.msb with
|
match x.msb, y.msb with
|
||||||
| false, false => umod s t
|
| false, false => umod x y
|
||||||
| false, true => umod s (.neg t)
|
| false, true => umod x (.neg y)
|
||||||
| true, false => .neg (umod (.neg s) t)
|
| true, false => .neg (umod (.neg x) y)
|
||||||
| true, true => .neg (umod (.neg s) (.neg t))
|
| true, true => .neg (umod (.neg x) (.neg y))
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Remainder for signed division rounded to negative infinity.
|
Remainder for signed division rounded to negative infinity.
|
||||||
|
|
||||||
SMT_Lib name: `bvsmod`.
|
SMT_Lib name: `bvsmod`.
|
||||||
-/
|
-/
|
||||||
def smod (s t : BitVec m) : BitVec m :=
|
def smod (x y : BitVec m) : BitVec m :=
|
||||||
match s.msb, t.msb with
|
match x.msb, y.msb with
|
||||||
| false, false => umod s t
|
| false, false => umod x y
|
||||||
| false, true =>
|
| false, true =>
|
||||||
let u := umod s (.neg t)
|
let u := umod x (.neg y)
|
||||||
(if u = .zero m then u else .add u t)
|
(if u = .zero m then u else .add u y)
|
||||||
| true, false =>
|
| true, false =>
|
||||||
let u := umod (.neg s) t
|
let u := umod (.neg x) y
|
||||||
(if u = .zero m then u else .sub t u)
|
(if u = .zero m then u else .sub y u)
|
||||||
| true, true => .neg (umod (.neg s) (.neg t))
|
| true, true => .neg (umod (.neg x) (.neg y))
|
||||||
|
|
||||||
end arithmetic
|
end arithmetic
|
||||||
|
|
||||||
@@ -371,8 +373,8 @@ end relations
|
|||||||
|
|
||||||
section cast
|
section cast
|
||||||
|
|
||||||
/-- `cast eq i` embeds `i` into an equal `BitVec` type. -/
|
/-- `cast eq x` embeds `x` into an equal `BitVec` type. -/
|
||||||
@[inline] def cast (eq : n = m) (i : BitVec n) : BitVec m := .ofNatLt i.toNat (eq ▸ i.isLt)
|
@[inline] def cast (eq : n = m) (x : BitVec n) : BitVec m := .ofNatLt x.toNat (eq ▸ x.isLt)
|
||||||
|
|
||||||
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
|
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
|
||||||
cast h (BitVec.ofNat n x) = BitVec.ofNat m x := by
|
cast h (BitVec.ofNat n x) = BitVec.ofNat m x := by
|
||||||
@@ -389,7 +391,7 @@ Extraction of bits `start` to `start + len - 1` from a bit vector of size `n` to
|
|||||||
new bitvector of size `len`. If `start + len > n`, then the vector will be zero-padded in the
|
new bitvector of size `len`. If `start + len > n`, then the vector will be zero-padded in the
|
||||||
high bits.
|
high bits.
|
||||||
-/
|
-/
|
||||||
def extractLsb' (start len : Nat) (a : BitVec n) : BitVec len := .ofNat _ (a.toNat >>> start)
|
def extractLsb' (start len : Nat) (x : BitVec n) : BitVec len := .ofNat _ (x.toNat >>> start)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Extraction of bits `hi` (inclusive) down to `lo` (inclusive) from a bit vector of size `n` to
|
Extraction of bits `hi` (inclusive) down to `lo` (inclusive) from a bit vector of size `n` to
|
||||||
@@ -397,12 +399,12 @@ yield a new bitvector of size `hi - lo + 1`.
|
|||||||
|
|
||||||
SMT-Lib name: `extract`.
|
SMT-Lib name: `extract`.
|
||||||
-/
|
-/
|
||||||
def extractLsb (hi lo : Nat) (a : BitVec n) : BitVec (hi - lo + 1) := extractLsb' lo _ a
|
def extractLsb (hi lo : Nat) (x : BitVec n) : BitVec (hi - lo + 1) := extractLsb' lo _ x
|
||||||
|
|
||||||
/--
|
/--
|
||||||
A version of `zeroExtend` that requires a proof, but is a noop.
|
A version of `zeroExtend` that requires a proof, but is a noop.
|
||||||
-/
|
-/
|
||||||
def zeroExtend' {n w : Nat} (le : n ≤ w) (x : BitVec n) : BitVec w :=
|
def zeroExtend' {n w : Nat} (le : n ≤ w) (x : BitVec n) : BitVec w :=
|
||||||
x.toNat#'(by
|
x.toNat#'(by
|
||||||
apply Nat.lt_of_lt_of_le x.isLt
|
apply Nat.lt_of_lt_of_le x.isLt
|
||||||
exact Nat.pow_le_pow_of_le_right (by trivial) le)
|
exact Nat.pow_le_pow_of_le_right (by trivial) le)
|
||||||
@@ -411,8 +413,8 @@ def zeroExtend' {n w : Nat} (le : n ≤ w) (x : BitVec n) : BitVec w :=
|
|||||||
`shiftLeftZeroExtend x n` returns `zeroExtend (w+n) x <<< n` without
|
`shiftLeftZeroExtend x n` returns `zeroExtend (w+n) x <<< n` without
|
||||||
needing to compute `x % 2^(2+n)`.
|
needing to compute `x % 2^(2+n)`.
|
||||||
-/
|
-/
|
||||||
def shiftLeftZeroExtend (msbs : BitVec w) (m : Nat) : BitVec (w+m) :=
|
def shiftLeftZeroExtend (msbs : BitVec w) (m : Nat) : BitVec (w + m) :=
|
||||||
let shiftLeftLt {x : Nat} (p : x < 2^w) (m : Nat) : x <<< m < 2^(w+m) := by
|
let shiftLeftLt {x : Nat} (p : x < 2^w) (m : Nat) : x <<< m < 2^(w + m) := by
|
||||||
simp [Nat.shiftLeft_eq, Nat.pow_add]
|
simp [Nat.shiftLeft_eq, Nat.pow_add]
|
||||||
apply Nat.mul_lt_mul_of_pos_right p
|
apply Nat.mul_lt_mul_of_pos_right p
|
||||||
exact (Nat.two_pow_pos m)
|
exact (Nat.two_pow_pos m)
|
||||||
@@ -500,24 +502,24 @@ instance : Complement (BitVec w) := ⟨.not⟩
|
|||||||
|
|
||||||
/--
|
/--
|
||||||
Left shift for bit vectors. The low bits are filled with zeros. As a numeric operation, this is
|
Left shift for bit vectors. The low bits are filled with zeros. As a numeric operation, this is
|
||||||
equivalent to `a * 2^s`, modulo `2^n`.
|
equivalent to `x * 2^s`, modulo `2^n`.
|
||||||
|
|
||||||
SMT-Lib name: `bvshl` except this operator uses a `Nat` shift value.
|
SMT-Lib name: `bvshl` except this operator uses a `Nat` shift value.
|
||||||
-/
|
-/
|
||||||
protected def shiftLeft (a : BitVec n) (s : Nat) : BitVec n := (a.toNat <<< s)#n
|
protected def shiftLeft (x : BitVec n) (s : Nat) : BitVec n := BitVec.ofNat n (x.toNat <<< s)
|
||||||
instance : HShiftLeft (BitVec w) Nat (BitVec w) := ⟨.shiftLeft⟩
|
instance : HShiftLeft (BitVec w) Nat (BitVec w) := ⟨.shiftLeft⟩
|
||||||
|
|
||||||
/--
|
/--
|
||||||
(Logical) right shift for bit vectors. The high bits are filled with zeros.
|
(Logical) right shift for bit vectors. The high bits are filled with zeros.
|
||||||
As a numeric operation, this is equivalent to `a / 2^s`, rounding down.
|
As a numeric operation, this is equivalent to `x / 2^s`, rounding down.
|
||||||
|
|
||||||
SMT-Lib name: `bvlshr` except this operator uses a `Nat` shift value.
|
SMT-Lib name: `bvlshr` except this operator uses a `Nat` shift value.
|
||||||
-/
|
-/
|
||||||
def ushiftRight (a : BitVec n) (s : Nat) : BitVec n :=
|
def ushiftRight (x : BitVec n) (s : Nat) : BitVec n :=
|
||||||
(a.toNat >>> s)#'(by
|
(x.toNat >>> s)#'(by
|
||||||
let ⟨a, lt⟩ := a
|
let ⟨x, lt⟩ := x
|
||||||
simp only [BitVec.toNat, Nat.shiftRight_eq_div_pow, Nat.div_lt_iff_lt_mul (Nat.two_pow_pos s)]
|
simp only [BitVec.toNat, Nat.shiftRight_eq_div_pow, Nat.div_lt_iff_lt_mul (Nat.two_pow_pos s)]
|
||||||
rw [←Nat.mul_one a]
|
rw [←Nat.mul_one x]
|
||||||
exact Nat.mul_lt_mul_of_lt_of_le' lt (Nat.two_pow_pos s) (Nat.le_refl 1))
|
exact Nat.mul_lt_mul_of_lt_of_le' lt (Nat.two_pow_pos s) (Nat.le_refl 1))
|
||||||
|
|
||||||
instance : HShiftRight (BitVec w) Nat (BitVec w) := ⟨.ushiftRight⟩
|
instance : HShiftRight (BitVec w) Nat (BitVec w) := ⟨.ushiftRight⟩
|
||||||
@@ -525,15 +527,29 @@ instance : HShiftRight (BitVec w) Nat (BitVec w) := ⟨.ushiftRight⟩
|
|||||||
/--
|
/--
|
||||||
Arithmetic right shift for bit vectors. The high bits are filled with the
|
Arithmetic right shift for bit vectors. The high bits are filled with the
|
||||||
most-significant bit.
|
most-significant bit.
|
||||||
As a numeric operation, this is equivalent to `a.toInt >>> s`.
|
As a numeric operation, this is equivalent to `x.toInt >>> s`.
|
||||||
|
|
||||||
SMT-Lib name: `bvashr` except this operator uses a `Nat` shift value.
|
SMT-Lib name: `bvashr` except this operator uses a `Nat` shift value.
|
||||||
-/
|
-/
|
||||||
def sshiftRight (a : BitVec n) (s : Nat) : BitVec n := .ofInt n (a.toInt >>> s)
|
def sshiftRight (x : BitVec n) (s : Nat) : BitVec n := .ofInt n (x.toInt >>> s)
|
||||||
|
|
||||||
instance {n} : HShiftLeft (BitVec m) (BitVec n) (BitVec m) := ⟨fun x y => x <<< y.toNat⟩
|
instance {n} : HShiftLeft (BitVec m) (BitVec n) (BitVec m) := ⟨fun x y => x <<< y.toNat⟩
|
||||||
instance {n} : HShiftRight (BitVec m) (BitVec n) (BitVec m) := ⟨fun x y => x >>> y.toNat⟩
|
instance {n} : HShiftRight (BitVec m) (BitVec n) (BitVec m) := ⟨fun x y => x >>> y.toNat⟩
|
||||||
|
|
||||||
|
/--
|
||||||
|
Arithmetic right shift for bit vectors. The high bits are filled with the
|
||||||
|
most-significant bit.
|
||||||
|
As a numeric operation, this is equivalent to `a.toInt >>> s.toNat`.
|
||||||
|
|
||||||
|
SMT-Lib name: `bvashr`.
|
||||||
|
-/
|
||||||
|
def sshiftRight' (a : BitVec n) (s : BitVec m) : BitVec n := a.sshiftRight s.toNat
|
||||||
|
|
||||||
|
/-- Auxiliary function for `rotateLeft`, which does not take into account the case where
|
||||||
|
the rotation amount is greater than the bitvector width. -/
|
||||||
|
def rotateLeftAux (x : BitVec w) (n : Nat) : BitVec w :=
|
||||||
|
x <<< n ||| x >>> (w - n)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Rotate left for bit vectors. All the bits of `x` are shifted to higher positions, with the top `n`
|
Rotate left for bit vectors. All the bits of `x` are shifted to higher positions, with the top `n`
|
||||||
bits wrapping around to fill the low bits.
|
bits wrapping around to fill the low bits.
|
||||||
@@ -543,7 +559,15 @@ rotateLeft 0b0011#4 3 = 0b1001
|
|||||||
```
|
```
|
||||||
SMT-Lib name: `rotate_left` except this operator uses a `Nat` shift amount.
|
SMT-Lib name: `rotate_left` except this operator uses a `Nat` shift amount.
|
||||||
-/
|
-/
|
||||||
def rotateLeft (x : BitVec w) (n : Nat) : BitVec w := x <<< n ||| x >>> (w - n)
|
def rotateLeft (x : BitVec w) (n : Nat) : BitVec w := rotateLeftAux x (n % w)
|
||||||
|
|
||||||
|
|
||||||
|
/--
|
||||||
|
Auxiliary function for `rotateRight`, which does not take into account the case where
|
||||||
|
the rotation amount is greater than the bitvector width.
|
||||||
|
-/
|
||||||
|
def rotateRightAux (x : BitVec w) (n : Nat) : BitVec w :=
|
||||||
|
x >>> n ||| x <<< (w - n)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Rotate right for bit vectors. All the bits of `x` are shifted to lower positions, with the
|
Rotate right for bit vectors. All the bits of `x` are shifted to lower positions, with the
|
||||||
@@ -554,7 +578,7 @@ rotateRight 0b01001#5 1 = 0b10100
|
|||||||
```
|
```
|
||||||
SMT-Lib name: `rotate_right` except this operator uses a `Nat` shift amount.
|
SMT-Lib name: `rotate_right` except this operator uses a `Nat` shift amount.
|
||||||
-/
|
-/
|
||||||
def rotateRight (x : BitVec w) (n : Nat) : BitVec w := x >>> n ||| x <<< (w - n)
|
def rotateRight (x : BitVec w) (n : Nat) : BitVec w := rotateRightAux x (n % w)
|
||||||
|
|
||||||
/--
|
/--
|
||||||
Concatenation of bitvectors. This uses the "big endian" convention that the more significant
|
Concatenation of bitvectors. This uses the "big endian" convention that the more significant
|
||||||
@@ -570,11 +594,9 @@ instance : HAppend (BitVec w) (BitVec v) (BitVec (w + v)) := ⟨.append⟩
|
|||||||
-- TODO: write this using multiplication
|
-- TODO: write this using multiplication
|
||||||
/-- `replicate i x` concatenates `i` copies of `x` into a new vector of length `w*i`. -/
|
/-- `replicate i x` concatenates `i` copies of `x` into a new vector of length `w*i`. -/
|
||||||
def replicate : (i : Nat) → BitVec w → BitVec (w*i)
|
def replicate : (i : Nat) → BitVec w → BitVec (w*i)
|
||||||
| 0, _ => 0
|
| 0, _ => 0#0
|
||||||
| n+1, x =>
|
| n+1, x =>
|
||||||
have hEq : w + w*n = w*(n + 1) := by
|
(x ++ replicate n x).cast (by rw [Nat.mul_succ]; omega)
|
||||||
rw [Nat.mul_add, Nat.add_comm, Nat.mul_one]
|
|
||||||
hEq ▸ (x ++ replicate n x)
|
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
### Cons and Concat
|
### Cons and Concat
|
||||||
@@ -601,6 +623,13 @@ theorem ofBool_append (msb : Bool) (lsbs : BitVec w) :
|
|||||||
ofBool msb ++ lsbs = (cons msb lsbs).cast (Nat.add_comm ..) :=
|
ofBool msb ++ lsbs = (cons msb lsbs).cast (Nat.add_comm ..) :=
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
|
/--
|
||||||
|
`twoPow w i` is the bitvector `2^i` if `i < w`, and `0` otherwise.
|
||||||
|
That is, 2 to the power `i`.
|
||||||
|
For the bitwise point of view, it has the `i`th bit as `1` and all other bits as `0`.
|
||||||
|
-/
|
||||||
|
def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i
|
||||||
|
|
||||||
end bitwise
|
end bitwise
|
||||||
|
|
||||||
section normalization_eqs
|
section normalization_eqs
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ https://github.com/mhk119/lean-smt/blob/bitvec/Smt/Data/Bitwise.lean.
|
|||||||
|
|
||||||
-/
|
-/
|
||||||
|
|
||||||
|
set_option linter.missingDocs true
|
||||||
|
|
||||||
open Nat Bool
|
open Nat Bool
|
||||||
|
|
||||||
namespace Bool
|
namespace Bool
|
||||||
@@ -98,6 +100,37 @@ theorem carry_succ (i : Nat) (x y : BitVec w) (c : Bool) :
|
|||||||
exact mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ ..
|
exact mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ ..
|
||||||
cases x.toNat.testBit i <;> cases y.toNat.testBit i <;> (simp; omega)
|
cases x.toNat.testBit i <;> cases y.toNat.testBit i <;> (simp; omega)
|
||||||
|
|
||||||
|
/--
|
||||||
|
If `x &&& y = 0`, then the carry bit `(x + y + 0)` is always `false` for any index `i`.
|
||||||
|
Intuitively, this is because a carry is only produced when at least two of `x`, `y`, and the
|
||||||
|
previous carry are true. However, since `x &&& y = 0`, at most one of `x, y` can be true,
|
||||||
|
and thus we never have a previous carry, which means that the sum cannot produce a carry.
|
||||||
|
-/
|
||||||
|
theorem carry_of_and_eq_zero {x y : BitVec w} (h : x &&& y = 0#w) : carry i x y false = false := by
|
||||||
|
induction i with
|
||||||
|
| zero => simp
|
||||||
|
| succ i ih =>
|
||||||
|
replace h := congrArg (·.getLsb i) h
|
||||||
|
simp_all [carry_succ]
|
||||||
|
|
||||||
|
/-- The final carry bit when computing `x + y + c` is `true` iff `x.toNat + y.toNat + c.toNat ≥ 2^w`. -/
|
||||||
|
theorem carry_width {x y : BitVec w} :
|
||||||
|
carry w x y c = decide (x.toNat + y.toNat + c.toNat ≥ 2^w) := by
|
||||||
|
simp [carry]
|
||||||
|
|
||||||
|
/--
|
||||||
|
If `x &&& y = 0`, then addition does not overflow, and thus `(x + y).toNat = x.toNat + y.toNat`.
|
||||||
|
-/
|
||||||
|
theorem toNat_add_of_and_eq_zero {x y : BitVec w} (h : x &&& y = 0#w) :
|
||||||
|
(x + y).toNat = x.toNat + y.toNat := by
|
||||||
|
rw [toNat_add]
|
||||||
|
apply Nat.mod_eq_of_lt
|
||||||
|
suffices ¬ decide (x.toNat + y.toNat + false.toNat ≥ 2^w) by
|
||||||
|
simp only [decide_eq_true_eq] at this
|
||||||
|
omega
|
||||||
|
rw [← carry_width]
|
||||||
|
simp [not_eq_true, carry_of_and_eq_zero h]
|
||||||
|
|
||||||
/-- Carry function for bitwise addition. -/
|
/-- Carry function for bitwise addition. -/
|
||||||
def adcb (x y c : Bool) : Bool × Bool := (atLeastTwo x y c, Bool.xor x (Bool.xor y c))
|
def adcb (x y c : Bool) : Bool × Bool := (atLeastTwo x y c, Bool.xor x (Bool.xor y c))
|
||||||
|
|
||||||
@@ -159,6 +192,21 @@ theorem add_eq_adc (w : Nat) (x y : BitVec w) : x + y = (adc x y false).snd := b
|
|||||||
theorem allOnes_sub_eq_not (x : BitVec w) : allOnes w - x = ~~~x := by
|
theorem allOnes_sub_eq_not (x : BitVec w) : allOnes w - x = ~~~x := by
|
||||||
rw [← add_not_self x, BitVec.add_comm, add_sub_cancel]
|
rw [← add_not_self x, BitVec.add_comm, add_sub_cancel]
|
||||||
|
|
||||||
|
/-- Addition of bitvectors is the same as bitwise or, if bitwise and is zero. -/
|
||||||
|
theorem add_eq_or_of_and_eq_zero {w : Nat} (x y : BitVec w)
|
||||||
|
(h : x &&& y = 0#w) : x + y = x ||| y := by
|
||||||
|
rw [add_eq_adc, adc, iunfoldr_replace (fun _ => false) (x ||| y)]
|
||||||
|
· rfl
|
||||||
|
· simp only [adcb, atLeastTwo, Bool.and_false, Bool.or_false, bne_false, getLsb_or,
|
||||||
|
Prod.mk.injEq, and_eq_false_imp]
|
||||||
|
intros i
|
||||||
|
replace h : (x &&& y).getLsb i = (0#w).getLsb i := by rw [h]
|
||||||
|
simp only [getLsb_and, getLsb_zero, and_eq_false_imp] at h
|
||||||
|
constructor
|
||||||
|
· intros hx
|
||||||
|
simp_all [hx]
|
||||||
|
· by_cases hx : x.getLsb i <;> simp_all [hx]
|
||||||
|
|
||||||
/-! ### Negation -/
|
/-! ### Negation -/
|
||||||
|
|
||||||
theorem bit_not_testBit (x : BitVec w) (i : Fin w) :
|
theorem bit_not_testBit (x : BitVec w) (i : Fin w) :
|
||||||
@@ -198,4 +246,311 @@ theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
|||||||
theorem ule_eq_carry (x y : BitVec w) : x.ule y = carry w y (~~~x) true := by
|
theorem ule_eq_carry (x y : BitVec w) : x.ule y = carry w y (~~~x) true := by
|
||||||
simp [ule_eq_not_ult, ult_eq_not_carry]
|
simp [ule_eq_not_ult, ult_eq_not_carry]
|
||||||
|
|
||||||
|
/-- If two bitvectors have the same `msb`, then signed and unsigned comparisons coincide -/
|
||||||
|
theorem slt_eq_ult_of_msb_eq {x y : BitVec w} (h : x.msb = y.msb) :
|
||||||
|
x.slt y = x.ult y := by
|
||||||
|
simp only [BitVec.slt, toInt_eq_msb_cond, BitVec.ult, decide_eq_decide, h]
|
||||||
|
cases y.msb <;> simp
|
||||||
|
|
||||||
|
/-- If two bitvectors have different `msb`s, then unsigned comparison is determined by this bit -/
|
||||||
|
theorem ult_eq_msb_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||||
|
x.ult y = y.msb := by
|
||||||
|
simp only [BitVec.ult, msb_eq_decide, ne_eq, decide_eq_decide] at *
|
||||||
|
omega
|
||||||
|
|
||||||
|
/-- If two bitvectors have different `msb`s, then signed and unsigned comparisons are opposites -/
|
||||||
|
theorem slt_eq_not_ult_of_msb_neq {x y : BitVec w} (h : x.msb ≠ y.msb) :
|
||||||
|
x.slt y = !x.ult y := by
|
||||||
|
simp only [BitVec.slt, toInt_eq_msb_cond, Bool.eq_not_of_ne h, ult_eq_msb_of_msb_neq h]
|
||||||
|
cases y.msb <;> (simp; omega)
|
||||||
|
|
||||||
|
theorem slt_eq_ult (x y : BitVec w) :
|
||||||
|
x.slt y = (x.msb != y.msb).xor (x.ult y) := by
|
||||||
|
by_cases h : x.msb = y.msb
|
||||||
|
· simp [h, slt_eq_ult_of_msb_eq]
|
||||||
|
· have h' : x.msb != y.msb := by simp_all
|
||||||
|
simp [slt_eq_not_ult_of_msb_neq h, h']
|
||||||
|
|
||||||
|
theorem slt_eq_not_carry (x y : BitVec w) :
|
||||||
|
x.slt y = (x.msb == y.msb).xor (carry w x (~~~y) true) := by
|
||||||
|
simp only [slt_eq_ult, bne, ult_eq_not_carry]
|
||||||
|
cases x.msb == y.msb <;> simp
|
||||||
|
|
||||||
|
theorem sle_eq_not_slt (x y : BitVec w) : x.sle y = !y.slt x := by
|
||||||
|
simp only [BitVec.sle, BitVec.slt, ← decide_not, decide_eq_decide]; omega
|
||||||
|
|
||||||
|
theorem sle_eq_carry (x y : BitVec w) :
|
||||||
|
x.sle y = !((x.msb == y.msb).xor (carry w y (~~~x) true)) := by
|
||||||
|
rw [sle_eq_not_slt, slt_eq_not_carry, beq_comm]
|
||||||
|
|
||||||
|
/-! ### mul recurrence for bitblasting -/
|
||||||
|
|
||||||
|
/--
|
||||||
|
A recurrence that describes multiplication as repeated addition.
|
||||||
|
Is useful for bitblasting multiplication.
|
||||||
|
-/
|
||||||
|
def mulRec (x y : BitVec w) (s : Nat) : BitVec w :=
|
||||||
|
let cur := if y.getLsb s then (x <<< s) else 0
|
||||||
|
match s with
|
||||||
|
| 0 => cur
|
||||||
|
| s + 1 => mulRec x y s + cur
|
||||||
|
|
||||||
|
theorem mulRec_zero_eq (x y : BitVec w) :
|
||||||
|
mulRec x y 0 = if y.getLsb 0 then x else 0 := by
|
||||||
|
simp [mulRec]
|
||||||
|
|
||||||
|
theorem mulRec_succ_eq (x y : BitVec w) (s : Nat) :
|
||||||
|
mulRec x y (s + 1) = mulRec x y s + if y.getLsb (s + 1) then (x <<< (s + 1)) else 0 := rfl
|
||||||
|
|
||||||
|
/--
|
||||||
|
Recurrence lemma: truncating to `i+1` bits and then zero extending to `w`
|
||||||
|
equals truncating upto `i` bits `[0..i-1]`, and then adding the `i`th bit of `x`.
|
||||||
|
-/
|
||||||
|
theorem zeroExtend_truncate_succ_eq_zeroExtend_truncate_add_twoPow (x : BitVec w) (i : Nat) :
|
||||||
|
zeroExtend w (x.truncate (i + 1)) =
|
||||||
|
zeroExtend w (x.truncate i) + (x &&& twoPow w i) := by
|
||||||
|
rw [add_eq_or_of_and_eq_zero]
|
||||||
|
· ext k
|
||||||
|
simp only [getLsb_zeroExtend, Fin.is_lt, decide_True, Bool.true_and, getLsb_or, getLsb_and]
|
||||||
|
by_cases hik : i = k
|
||||||
|
· subst hik
|
||||||
|
simp
|
||||||
|
· simp only [getLsb_twoPow, hik, decide_False, Bool.and_false, Bool.or_false]
|
||||||
|
by_cases hik' : k < (i + 1)
|
||||||
|
· have hik'' : k < i := by omega
|
||||||
|
simp [hik', hik'']
|
||||||
|
· have hik'' : ¬ (k < i) := by omega
|
||||||
|
simp [hik', hik'']
|
||||||
|
· ext k
|
||||||
|
simp
|
||||||
|
by_cases hi : x.getLsb i <;> simp [hi] <;> omega
|
||||||
|
|
||||||
|
/--
|
||||||
|
Recurrence lemma: multiplying `x` with the first `s` bits of `y` is the
|
||||||
|
same as truncating `y` to `s` bits, then zero extending to the original length,
|
||||||
|
and performing the multplication. -/
|
||||||
|
theorem mulRec_eq_mul_signExtend_truncate (x y : BitVec w) (s : Nat) :
|
||||||
|
mulRec x y s = x * ((y.truncate (s + 1)).zeroExtend w) := by
|
||||||
|
induction s
|
||||||
|
case zero =>
|
||||||
|
simp only [mulRec_zero_eq, ofNat_eq_ofNat, Nat.reduceAdd]
|
||||||
|
by_cases y.getLsb 0
|
||||||
|
case pos hy =>
|
||||||
|
simp only [hy, ↓reduceIte, truncate, zeroExtend_one_eq_ofBool_getLsb_zero,
|
||||||
|
ofBool_true, ofNat_eq_ofNat]
|
||||||
|
rw [zeroExtend_ofNat_one_eq_ofNat_one_of_lt (by omega)]
|
||||||
|
simp
|
||||||
|
case neg hy =>
|
||||||
|
simp [hy, zeroExtend_one_eq_ofBool_getLsb_zero]
|
||||||
|
case succ s' hs =>
|
||||||
|
rw [mulRec_succ_eq, hs]
|
||||||
|
have heq :
|
||||||
|
(if y.getLsb (s' + 1) = true then x <<< (s' + 1) else 0) =
|
||||||
|
(x * (y &&& (BitVec.twoPow w (s' + 1)))) := by
|
||||||
|
simp only [ofNat_eq_ofNat, and_twoPow]
|
||||||
|
by_cases hy : y.getLsb (s' + 1) <;> simp [hy]
|
||||||
|
rw [heq, ← BitVec.mul_add, ← zeroExtend_truncate_succ_eq_zeroExtend_truncate_add_twoPow]
|
||||||
|
|
||||||
|
theorem getLsb_mul (x y : BitVec w) (i : Nat) :
|
||||||
|
(x * y).getLsb i = (mulRec x y w).getLsb i := by
|
||||||
|
simp only [mulRec_eq_mul_signExtend_truncate]
|
||||||
|
rw [truncate, ← truncate_eq_zeroExtend, ← truncate_eq_zeroExtend,
|
||||||
|
truncate_truncate_of_le]
|
||||||
|
· simp
|
||||||
|
· omega
|
||||||
|
|
||||||
|
/-! ## shiftLeft recurrence for bitblasting -/
|
||||||
|
|
||||||
|
/--
|
||||||
|
`shiftLeftRec x y n` shifts `x` to the left by the first `n` bits of `y`.
|
||||||
|
|
||||||
|
The theorem `shiftLeft_eq_shiftLeftRec` proves the equivalence of `(x <<< y)` and `shiftLeftRec`.
|
||||||
|
|
||||||
|
Together with equations `shiftLeftRec_zero`, `shiftLeftRec_succ`,
|
||||||
|
this allows us to unfold `shiftLeft` into a circuit for bitblasting.
|
||||||
|
-/
|
||||||
|
def shiftLeftRec (x : BitVec w₁) (y : BitVec w₂) (n : Nat) : BitVec w₁ :=
|
||||||
|
let shiftAmt := (y &&& (twoPow w₂ n))
|
||||||
|
match n with
|
||||||
|
| 0 => x <<< shiftAmt
|
||||||
|
| n + 1 => (shiftLeftRec x y n) <<< shiftAmt
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem shiftLeftRec_zero {x : BitVec w₁} {y : BitVec w₂} :
|
||||||
|
shiftLeftRec x y 0 = x <<< (y &&& twoPow w₂ 0) := by
|
||||||
|
simp [shiftLeftRec]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem shiftLeftRec_succ {x : BitVec w₁} {y : BitVec w₂} :
|
||||||
|
shiftLeftRec x y (n + 1) = (shiftLeftRec x y n) <<< (y &&& twoPow w₂ (n + 1)) := by
|
||||||
|
simp [shiftLeftRec]
|
||||||
|
|
||||||
|
/--
|
||||||
|
If `y &&& z = 0`, `x <<< (y ||| z) = x <<< y <<< z`.
|
||||||
|
This follows as `y &&& z = 0` implies `y ||| z = y + z`,
|
||||||
|
and thus `x <<< (y ||| z) = x <<< (y + z) = x <<< y <<< z`.
|
||||||
|
-/
|
||||||
|
theorem shiftLeft_or_of_and_eq_zero {x : BitVec w₁} {y z : BitVec w₂}
|
||||||
|
(h : y &&& z = 0#w₂) :
|
||||||
|
x <<< (y ||| z) = x <<< y <<< z := by
|
||||||
|
rw [← add_eq_or_of_and_eq_zero _ _ h,
|
||||||
|
shiftLeft_eq', toNat_add_of_and_eq_zero h]
|
||||||
|
simp [shiftLeft_add]
|
||||||
|
|
||||||
|
/--
|
||||||
|
`shiftLeftRec x y n` shifts `x` to the left by the first `n` bits of `y`.
|
||||||
|
-/
|
||||||
|
theorem shiftLeftRec_eq {x : BitVec w₁} {y : BitVec w₂} {n : Nat} :
|
||||||
|
shiftLeftRec x y n = x <<< (y.truncate (n + 1)).zeroExtend w₂ := by
|
||||||
|
induction n generalizing x y
|
||||||
|
case zero =>
|
||||||
|
ext i
|
||||||
|
simp only [shiftLeftRec_zero, twoPow_zero, Nat.reduceAdd, truncate_one,
|
||||||
|
and_one_eq_zeroExtend_ofBool_getLsb]
|
||||||
|
case succ n ih =>
|
||||||
|
simp only [shiftLeftRec_succ, and_twoPow]
|
||||||
|
rw [ih]
|
||||||
|
by_cases h : y.getLsb (n + 1)
|
||||||
|
· simp only [h, ↓reduceIte]
|
||||||
|
rw [zeroExtend_truncate_succ_eq_zeroExtend_truncate_or_twoPow_of_getLsb_true h,
|
||||||
|
shiftLeft_or_of_and_eq_zero]
|
||||||
|
simp
|
||||||
|
· simp only [h, false_eq_true, ↓reduceIte, shiftLeft_zero']
|
||||||
|
rw [zeroExtend_truncate_succ_eq_zeroExtend_truncate_of_getLsb_false (i := n + 1)]
|
||||||
|
simp [h]
|
||||||
|
|
||||||
|
/--
|
||||||
|
Show that `x <<< y` can be written in terms of `shiftLeftRec`.
|
||||||
|
This can be unfolded in terms of `shiftLeftRec_zero`, `shiftLeftRec_succ` for bitblasting.
|
||||||
|
-/
|
||||||
|
theorem shiftLeft_eq_shiftLeftRec (x : BitVec w₁) (y : BitVec w₂) :
|
||||||
|
x <<< y = shiftLeftRec x y (w₂ - 1) := by
|
||||||
|
rcases w₂ with rfl | w₂
|
||||||
|
· simp [of_length_zero]
|
||||||
|
· simp [shiftLeftRec_eq]
|
||||||
|
|
||||||
|
/- ### Arithmetic shift right (sshiftRight) recurrence -/
|
||||||
|
|
||||||
|
/--
|
||||||
|
`sshiftRightRec x y n` shifts `x` arithmetically/signed to the right by the first `n` bits of `y`.
|
||||||
|
The theorem `sshiftRight_eq_sshiftRightRec` proves the equivalence of `(x.sshiftRight y)` and `sshiftRightRec`.
|
||||||
|
Together with equations `sshiftRightRec_zero`, `sshiftRightRec_succ`,
|
||||||
|
this allows us to unfold `sshiftRight` into a circuit for bitblasting.
|
||||||
|
-/
|
||||||
|
def sshiftRightRec (x : BitVec w₁) (y : BitVec w₂) (n : Nat) : BitVec w₁ :=
|
||||||
|
let shiftAmt := (y &&& (twoPow w₂ n))
|
||||||
|
match n with
|
||||||
|
| 0 => x.sshiftRight' shiftAmt
|
||||||
|
| n + 1 => (sshiftRightRec x y n).sshiftRight' shiftAmt
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem sshiftRightRec_zero_eq (x : BitVec w₁) (y : BitVec w₂) :
|
||||||
|
sshiftRightRec x y 0 = x.sshiftRight' (y &&& 1#w₂) := by
|
||||||
|
simp only [sshiftRightRec, twoPow_zero]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem sshiftRightRec_succ_eq (x : BitVec w₁) (y : BitVec w₂) (n : Nat) :
|
||||||
|
sshiftRightRec x y (n + 1) = (sshiftRightRec x y n).sshiftRight' (y &&& twoPow w₂ (n + 1)) := by
|
||||||
|
simp [sshiftRightRec]
|
||||||
|
|
||||||
|
/--
|
||||||
|
If `y &&& z = 0`, `x.sshiftRight (y ||| z) = (x.sshiftRight y).sshiftRight z`.
|
||||||
|
This follows as `y &&& z = 0` implies `y ||| z = y + z`,
|
||||||
|
and thus `x.sshiftRight (y ||| z) = x.sshiftRight (y + z) = (x.sshiftRight y).sshiftRight z`.
|
||||||
|
-/
|
||||||
|
theorem sshiftRight'_or_of_and_eq_zero {x : BitVec w₁} {y z : BitVec w₂}
|
||||||
|
(h : y &&& z = 0#w₂) :
|
||||||
|
x.sshiftRight' (y ||| z) = (x.sshiftRight' y).sshiftRight' z := by
|
||||||
|
simp [sshiftRight', ← add_eq_or_of_and_eq_zero _ _ h,
|
||||||
|
toNat_add_of_and_eq_zero h, sshiftRight_add]
|
||||||
|
|
||||||
|
theorem sshiftRightRec_eq (x : BitVec w₁) (y : BitVec w₂) (n : Nat) :
|
||||||
|
sshiftRightRec x y n = x.sshiftRight' ((y.truncate (n + 1)).zeroExtend w₂) := by
|
||||||
|
induction n generalizing x y
|
||||||
|
case zero =>
|
||||||
|
ext i
|
||||||
|
simp [twoPow_zero, Nat.reduceAdd, and_one_eq_zeroExtend_ofBool_getLsb, truncate_one]
|
||||||
|
case succ n ih =>
|
||||||
|
simp only [sshiftRightRec_succ_eq, and_twoPow, ih]
|
||||||
|
by_cases h : y.getLsb (n + 1)
|
||||||
|
· rw [zeroExtend_truncate_succ_eq_zeroExtend_truncate_or_twoPow_of_getLsb_true h,
|
||||||
|
sshiftRight'_or_of_and_eq_zero (by simp), h]
|
||||||
|
simp
|
||||||
|
· rw [zeroExtend_truncate_succ_eq_zeroExtend_truncate_of_getLsb_false (i := n + 1)
|
||||||
|
(by simp [h])]
|
||||||
|
simp [h]
|
||||||
|
|
||||||
|
/--
|
||||||
|
Show that `x.sshiftRight y` can be written in terms of `sshiftRightRec`.
|
||||||
|
This can be unfolded in terms of `sshiftRightRec_zero_eq`, `sshiftRightRec_succ_eq` for bitblasting.
|
||||||
|
-/
|
||||||
|
theorem sshiftRight_eq_sshiftRightRec (x : BitVec w₁) (y : BitVec w₂) :
|
||||||
|
(x.sshiftRight' y).getLsb i = (sshiftRightRec x y (w₂ - 1)).getLsb i := by
|
||||||
|
rcases w₂ with rfl | w₂
|
||||||
|
· simp [of_length_zero]
|
||||||
|
· simp [sshiftRightRec_eq]
|
||||||
|
|
||||||
|
/- ### Logical shift right (ushiftRight) recurrence for bitblasting -/
|
||||||
|
|
||||||
|
/--
|
||||||
|
`ushiftRightRec x y n` shifts `x` logically to the right by the first `n` bits of `y`.
|
||||||
|
|
||||||
|
The theorem `shiftRight_eq_ushiftRightRec` proves the equivalence
|
||||||
|
of `(x >>> y)` and `ushiftRightRec`.
|
||||||
|
|
||||||
|
Together with equations `ushiftRightRec_zero`, `ushiftRightRec_succ`,
|
||||||
|
this allows us to unfold `ushiftRight` into a circuit for bitblasting.
|
||||||
|
-/
|
||||||
|
def ushiftRightRec (x : BitVec w₁) (y : BitVec w₂) (n : Nat) : BitVec w₁ :=
|
||||||
|
let shiftAmt := (y &&& (twoPow w₂ n))
|
||||||
|
match n with
|
||||||
|
| 0 => x >>> shiftAmt
|
||||||
|
| n + 1 => (ushiftRightRec x y n) >>> shiftAmt
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem ushiftRightRec_zero (x : BitVec w₁) (y : BitVec w₂) :
|
||||||
|
ushiftRightRec x y 0 = x >>> (y &&& twoPow w₂ 0) := by
|
||||||
|
simp [ushiftRightRec]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem ushiftRightRec_succ (x : BitVec w₁) (y : BitVec w₂) :
|
||||||
|
ushiftRightRec x y (n + 1) = (ushiftRightRec x y n) >>> (y &&& twoPow w₂ (n + 1)) := by
|
||||||
|
simp [ushiftRightRec]
|
||||||
|
|
||||||
|
/--
|
||||||
|
If `y &&& z = 0`, `x >>> (y ||| z) = x >>> y >>> z`.
|
||||||
|
This follows as `y &&& z = 0` implies `y ||| z = y + z`,
|
||||||
|
and thus `x >>> (y ||| z) = x >>> (y + z) = x >>> y >>> z`.
|
||||||
|
-/
|
||||||
|
theorem ushiftRight'_or_of_and_eq_zero {x : BitVec w₁} {y z : BitVec w₂}
|
||||||
|
(h : y &&& z = 0#w₂) :
|
||||||
|
x >>> (y ||| z) = x >>> y >>> z := by
|
||||||
|
simp [← add_eq_or_of_and_eq_zero _ _ h, toNat_add_of_and_eq_zero h, shiftRight_add]
|
||||||
|
|
||||||
|
theorem ushiftRightRec_eq (x : BitVec w₁) (y : BitVec w₂) (n : Nat) :
|
||||||
|
ushiftRightRec x y n = x >>> (y.truncate (n + 1)).zeroExtend w₂ := by
|
||||||
|
induction n generalizing x y
|
||||||
|
case zero =>
|
||||||
|
ext i
|
||||||
|
simp only [ushiftRightRec_zero, twoPow_zero, Nat.reduceAdd,
|
||||||
|
and_one_eq_zeroExtend_ofBool_getLsb, truncate_one]
|
||||||
|
case succ n ih =>
|
||||||
|
simp only [ushiftRightRec_succ, and_twoPow]
|
||||||
|
rw [ih]
|
||||||
|
by_cases h : y.getLsb (n + 1) <;> simp only [h, ↓reduceIte]
|
||||||
|
· rw [zeroExtend_truncate_succ_eq_zeroExtend_truncate_or_twoPow_of_getLsb_true h,
|
||||||
|
ushiftRight'_or_of_and_eq_zero]
|
||||||
|
simp
|
||||||
|
· simp [zeroExtend_truncate_succ_eq_zeroExtend_truncate_of_getLsb_false, h]
|
||||||
|
|
||||||
|
/--
|
||||||
|
Show that `x >>> y` can be written in terms of `ushiftRightRec`.
|
||||||
|
This can be unfolded in terms of `ushiftRightRec_zero`, `ushiftRightRec_succ` for bitblasting.
|
||||||
|
-/
|
||||||
|
theorem shiftRight_eq_ushiftRightRec (x : BitVec w₁) (y : BitVec w₂) :
|
||||||
|
x >>> y = ushiftRightRec x y (w₂ - 1) := by
|
||||||
|
rcases w₂ with rfl | w₂
|
||||||
|
· simp [of_length_zero]
|
||||||
|
· simp [ushiftRightRec_eq]
|
||||||
|
|
||||||
end BitVec
|
end BitVec
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import Init.Data.BitVec.Lemmas
|
|||||||
import Init.Data.Nat.Lemmas
|
import Init.Data.Nat.Lemmas
|
||||||
import Init.Data.Fin.Iterate
|
import Init.Data.Fin.Iterate
|
||||||
|
|
||||||
|
set_option linter.missingDocs true
|
||||||
|
|
||||||
namespace BitVec
|
namespace BitVec
|
||||||
|
|
||||||
/--
|
/--
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -52,8 +52,14 @@ theorem eq_iff_iff {a b : Bool} : a = b ↔ (a ↔ b) := by cases b <;> simp
|
|||||||
|
|
||||||
@[simp] theorem decide_eq_true {b : Bool} [Decidable (b = true)] : decide (b = true) = b := by cases b <;> simp
|
@[simp] theorem decide_eq_true {b : Bool} [Decidable (b = true)] : decide (b = true) = b := by cases b <;> simp
|
||||||
@[simp] theorem decide_eq_false {b : Bool} [Decidable (b = false)] : decide (b = false) = !b := by cases b <;> simp
|
@[simp] theorem decide_eq_false {b : Bool} [Decidable (b = false)] : decide (b = false) = !b := by cases b <;> simp
|
||||||
@[simp] theorem decide_true_eq {b : Bool} [Decidable (true = b)] : decide (true = b) = b := by cases b <;> simp
|
theorem decide_true_eq {b : Bool} [Decidable (true = b)] : decide (true = b) = b := by cases b <;> simp
|
||||||
@[simp] theorem decide_false_eq {b : Bool} [Decidable (false = b)] : decide (false = b) = !b := by cases b <;> simp
|
theorem decide_false_eq {b : Bool} [Decidable (false = b)] : decide (false = b) = !b := by cases b <;> simp
|
||||||
|
|
||||||
|
-- These lemmas assist with confluence.
|
||||||
|
@[simp] theorem eq_false_imp_eq_true_iff :
|
||||||
|
∀(a b : Bool), ((a = false → b = true) ↔ (b = false → a = true)) = True := by decide
|
||||||
|
@[simp] theorem eq_true_imp_eq_false_iff :
|
||||||
|
∀(a b : Bool), ((a = true → b = false) ↔ (b = true → a = false)) = True := by decide
|
||||||
|
|
||||||
/-! ### and -/
|
/-! ### and -/
|
||||||
|
|
||||||
@@ -91,6 +97,11 @@ Needed for confluence of term `(a && b) ↔ a` which reduces to `(a && b) = a` v
|
|||||||
@[simp] theorem iff_self_and : ∀(a b : Bool), (a = (a && b)) ↔ (a → b) := by decide
|
@[simp] theorem iff_self_and : ∀(a b : Bool), (a = (a && b)) ↔ (a → b) := by decide
|
||||||
@[simp] theorem iff_and_self : ∀(a b : Bool), (b = (a && b)) ↔ (b → a) := by decide
|
@[simp] theorem iff_and_self : ∀(a b : Bool), (b = (a && b)) ↔ (b → a) := by decide
|
||||||
|
|
||||||
|
@[simp] theorem not_and_iff_left_iff_imp : ∀ (a b : Bool), ((!a && b) = a) ↔ !a ∧ !b := by decide
|
||||||
|
@[simp] theorem and_not_iff_right_iff_imp : ∀ (a b : Bool), ((a && !b) = b) ↔ !a ∧ !b := by decide
|
||||||
|
@[simp] theorem iff_not_self_and : ∀ (a b : Bool), (a = (!a && b)) ↔ !a ∧ !b := by decide
|
||||||
|
@[simp] theorem iff_and_not_self : ∀ (a b : Bool), (b = (a && !b)) ↔ !a ∧ !b := by decide
|
||||||
|
|
||||||
/-! ### or -/
|
/-! ### or -/
|
||||||
|
|
||||||
@[simp] theorem or_self_left : ∀(a b : Bool), (a || (a || b)) = (a || b) := by decide
|
@[simp] theorem or_self_left : ∀(a b : Bool), (a || (a || b)) = (a || b) := by decide
|
||||||
@@ -120,6 +131,11 @@ Needed for confluence of term `(a || b) ↔ a` which reduces to `(a || b) = a` v
|
|||||||
@[simp] theorem iff_self_or : ∀(a b : Bool), (a = (a || b)) ↔ (b → a) := by decide
|
@[simp] theorem iff_self_or : ∀(a b : Bool), (a = (a || b)) ↔ (b → a) := by decide
|
||||||
@[simp] theorem iff_or_self : ∀(a b : Bool), (b = (a || b)) ↔ (a → b) := by decide
|
@[simp] theorem iff_or_self : ∀(a b : Bool), (b = (a || b)) ↔ (a → b) := by decide
|
||||||
|
|
||||||
|
@[simp] theorem not_or_iff_left_iff_imp : ∀ (a b : Bool), ((!a || b) = a) ↔ a ∧ b := by decide
|
||||||
|
@[simp] theorem or_not_iff_right_iff_imp : ∀ (a b : Bool), ((a || !b) = b) ↔ a ∧ b := by decide
|
||||||
|
@[simp] theorem iff_not_self_or : ∀ (a b : Bool), (a = (!a || b)) ↔ a ∧ b := by decide
|
||||||
|
@[simp] theorem iff_or_not_self : ∀ (a b : Bool), (b = (a || !b)) ↔ a ∧ b := by decide
|
||||||
|
|
||||||
theorem or_comm : ∀ (x y : Bool), (x || y) = (y || x) := by decide
|
theorem or_comm : ∀ (x y : Bool), (x || y) = (y || x) := by decide
|
||||||
instance : Std.Commutative (· || ·) := ⟨or_comm⟩
|
instance : Std.Commutative (· || ·) := ⟨or_comm⟩
|
||||||
|
|
||||||
@@ -134,7 +150,7 @@ theorem and_or_distrib_right : ∀ (x y z : Bool), ((x || y) && z) = (x && z ||
|
|||||||
theorem or_and_distrib_left : ∀ (x y z : Bool), (x || y && z) = ((x || y) && (x || z)) := by decide
|
theorem or_and_distrib_left : ∀ (x y z : Bool), (x || y && z) = ((x || y) && (x || z)) := by decide
|
||||||
theorem or_and_distrib_right : ∀ (x y z : Bool), (x && y || z) = ((x || z) && (y || z)) := by decide
|
theorem or_and_distrib_right : ∀ (x y z : Bool), (x && y || z) = ((x || z) && (y || z)) := by decide
|
||||||
|
|
||||||
theorem and_xor_distrib_left : ∀ (x y z : Bool), (x && xor y z) = xor (x && y) (x && z) := by decide
|
theorem and_xor_distrib_left : ∀ (x y z : Bool), (x && xor y z) = xor (x && y) (x && z) := by decide
|
||||||
theorem and_xor_distrib_right : ∀ (x y z : Bool), (xor x y && z) = xor (x && z) (y && z) := by decide
|
theorem and_xor_distrib_right : ∀ (x y z : Bool), (xor x y && z) = xor (x && z) (y && z) := by decide
|
||||||
|
|
||||||
/-- De Morgan's law for boolean and -/
|
/-- De Morgan's law for boolean and -/
|
||||||
@@ -163,7 +179,7 @@ Consider the term: `¬((b && c) = true)`:
|
|||||||
-/
|
-/
|
||||||
@[simp] theorem and_eq_false_imp : ∀ (x y : Bool), (x && y) = false ↔ (x = true → y = false) := by decide
|
@[simp] theorem and_eq_false_imp : ∀ (x y : Bool), (x && y) = false ↔ (x = true → y = false) := by decide
|
||||||
|
|
||||||
@[simp] theorem or_eq_true_iff : ∀ (x y : Bool), (x || y) = true ↔ x = true ∨ y = true := by decide
|
theorem or_eq_true_iff : ∀ (x y : Bool), (x || y) = true ↔ x = true ∨ y = true := by simp
|
||||||
|
|
||||||
@[simp] theorem or_eq_false_iff : ∀ (x y : Bool), (x || y) = false ↔ x = false ∧ y = false := by decide
|
@[simp] theorem or_eq_false_iff : ∀ (x y : Bool), (x || y) = false ↔ x = false ∧ y = false := by decide
|
||||||
|
|
||||||
@@ -187,11 +203,9 @@ in false_eq and true_eq.
|
|||||||
|
|
||||||
@[simp] theorem true_beq : ∀b, (true == b) = b := by decide
|
@[simp] theorem true_beq : ∀b, (true == b) = b := by decide
|
||||||
@[simp] theorem false_beq : ∀b, (false == b) = !b := by decide
|
@[simp] theorem false_beq : ∀b, (false == b) = !b := by decide
|
||||||
@[simp] theorem beq_true : ∀b, (b == true) = b := by decide
|
|
||||||
instance : Std.LawfulIdentity (· == ·) true where
|
instance : Std.LawfulIdentity (· == ·) true where
|
||||||
left_id := true_beq
|
left_id := true_beq
|
||||||
right_id := beq_true
|
right_id := beq_true
|
||||||
@[simp] theorem beq_false : ∀b, (b == false) = !b := by decide
|
|
||||||
|
|
||||||
@[simp] theorem true_bne : ∀(b : Bool), (true != b) = !b := by decide
|
@[simp] theorem true_bne : ∀(b : Bool), (true != b) = !b := by decide
|
||||||
@[simp] theorem false_bne : ∀(b : Bool), (false != b) = b := by decide
|
@[simp] theorem false_bne : ∀(b : Bool), (false != b) = b := by decide
|
||||||
@@ -204,8 +218,11 @@ instance : Std.LawfulIdentity (· != ·) false where
|
|||||||
@[simp] theorem not_beq_self : ∀ (x : Bool), ((!x) == x) = false := by decide
|
@[simp] theorem not_beq_self : ∀ (x : Bool), ((!x) == x) = false := by decide
|
||||||
@[simp] theorem beq_not_self : ∀ (x : Bool), (x == !x) = false := by decide
|
@[simp] theorem beq_not_self : ∀ (x : Bool), (x == !x) = false := by decide
|
||||||
|
|
||||||
@[simp] theorem not_bne_self : ∀ (x : Bool), ((!x) != x) = true := by decide
|
@[simp] theorem not_bne : ∀ (a b : Bool), ((!a) != b) = !(a != b) := by decide
|
||||||
@[simp] theorem bne_not_self : ∀ (x : Bool), (x != !x) = true := by decide
|
@[simp] theorem bne_not : ∀ (a b : Bool), (a != !b) = !(a != b) := by decide
|
||||||
|
|
||||||
|
theorem not_bne_self : ∀ (x : Bool), ((!x) != x) = true := by decide
|
||||||
|
theorem bne_not_self : ∀ (x : Bool), (x != !x) = true := by decide
|
||||||
|
|
||||||
/-
|
/-
|
||||||
Added for equivalence with `Bool.not_beq_self` and needed for confluence
|
Added for equivalence with `Bool.not_beq_self` and needed for confluence
|
||||||
@@ -227,6 +244,8 @@ instance : Std.Associative (· != ·) := ⟨bne_assoc⟩
|
|||||||
@[simp] theorem bne_left_inj : ∀ (x y z : Bool), (x != y) = (x != z) ↔ y = z := by decide
|
@[simp] theorem bne_left_inj : ∀ (x y z : Bool), (x != y) = (x != z) ↔ y = z := by decide
|
||||||
@[simp] theorem bne_right_inj : ∀ (x y z : Bool), (x != z) = (y != z) ↔ x = y := by decide
|
@[simp] theorem bne_right_inj : ∀ (x y z : Bool), (x != z) = (y != z) ↔ x = y := by decide
|
||||||
|
|
||||||
|
theorem eq_not_of_ne : ∀ {x y : Bool}, x ≠ y → x = !y := by decide
|
||||||
|
|
||||||
/-! ### coercision related normal forms -/
|
/-! ### coercision related normal forms -/
|
||||||
|
|
||||||
theorem beq_eq_decide_eq [BEq α] [LawfulBEq α] [DecidableEq α] (a b : α) :
|
theorem beq_eq_decide_eq [BEq α] [LawfulBEq α] [DecidableEq α] (a b : α) :
|
||||||
@@ -235,8 +254,10 @@ theorem beq_eq_decide_eq [BEq α] [LawfulBEq α] [DecidableEq α] (a b : α) :
|
|||||||
· simp [ne_of_beq_false h]
|
· simp [ne_of_beq_false h]
|
||||||
· simp [eq_of_beq h]
|
· simp [eq_of_beq h]
|
||||||
|
|
||||||
@[simp] theorem not_eq_not : ∀ {a b : Bool}, ¬a = !b ↔ a = b := by decide
|
theorem eq_not : ∀ (a b : Bool), (a = (!b)) ↔ (a ≠ b) := by decide
|
||||||
|
theorem not_eq : ∀ (a b : Bool), ((!a) = b) ↔ (a ≠ b) := by decide
|
||||||
|
|
||||||
|
@[simp] theorem not_eq_not : ∀ {a b : Bool}, ¬a = !b ↔ a = b := by decide
|
||||||
@[simp] theorem not_not_eq : ∀ {a b : Bool}, ¬(!a) = b ↔ a = b := by decide
|
@[simp] theorem not_not_eq : ∀ {a b : Bool}, ¬(!a) = b ↔ a = b := by decide
|
||||||
|
|
||||||
@[simp] theorem coe_iff_coe : ∀(a b : Bool), (a ↔ b) ↔ a = b := by decide
|
@[simp] theorem coe_iff_coe : ∀(a b : Bool), (a ↔ b) ↔ a = b := by decide
|
||||||
@@ -351,7 +372,7 @@ theorem and_or_inj_left_iff :
|
|||||||
/-! ## toNat -/
|
/-! ## toNat -/
|
||||||
|
|
||||||
/-- convert a `Bool` to a `Nat`, `false -> 0`, `true -> 1` -/
|
/-- convert a `Bool` to a `Nat`, `false -> 0`, `true -> 1` -/
|
||||||
def toNat (b:Bool) : Nat := cond b 1 0
|
def toNat (b : Bool) : Nat := cond b 1 0
|
||||||
|
|
||||||
@[simp] theorem toNat_false : false.toNat = 0 := rfl
|
@[simp] theorem toNat_false : false.toNat = 0 := rfl
|
||||||
|
|
||||||
@@ -360,9 +381,6 @@ def toNat (b:Bool) : Nat := cond b 1 0
|
|||||||
theorem toNat_le (c : Bool) : c.toNat ≤ 1 := by
|
theorem toNat_le (c : Bool) : c.toNat ≤ 1 := by
|
||||||
cases c <;> trivial
|
cases c <;> trivial
|
||||||
|
|
||||||
@[deprecated toNat_le (since := "2024-02-23")]
|
|
||||||
abbrev toNat_le_one := toNat_le
|
|
||||||
|
|
||||||
theorem toNat_lt (b : Bool) : b.toNat < 2 :=
|
theorem toNat_lt (b : Bool) : b.toNat < 2 :=
|
||||||
Nat.lt_succ_of_le (toNat_le _)
|
Nat.lt_succ_of_le (toNat_le _)
|
||||||
|
|
||||||
@@ -427,17 +445,37 @@ theorem not_ite_eq_false_eq_true (p : Prop) [h : Decidable p] (b c : Bool) :
|
|||||||
cases h with | _ p => simp [p]
|
cases h with | _ p => simp [p]
|
||||||
|
|
||||||
/-
|
/-
|
||||||
Added for confluence between `if_true_left` and `ite_false_same` on
|
It would be nice to have this for confluence between `if_true_left` and `ite_false_same` on
|
||||||
`if b = true then True else b = true`
|
`if b = true then True else b = true`.
|
||||||
|
However the discrimination tree key is just `→`, so this is tried too often.
|
||||||
-/
|
-/
|
||||||
@[simp] theorem eq_false_imp_eq_true : ∀(b:Bool), (b = false → b = true) ↔ (b = true) := by decide
|
theorem eq_false_imp_eq_true : ∀(b:Bool), (b = false → b = true) ↔ (b = true) := by decide
|
||||||
|
|
||||||
/-
|
/-
|
||||||
Added for confluence between `if_true_left` and `ite_false_same` on
|
It would be nice to have this for confluence between `if_true_left` and `ite_false_same` on
|
||||||
`if b = false then True else b = false`
|
`if b = false then True else b = false`.
|
||||||
|
However the discrimination tree key is just `→`, so this is tried too often.
|
||||||
-/
|
-/
|
||||||
@[simp] theorem eq_true_imp_eq_false : ∀(b:Bool), (b = true → b = false) ↔ (b = false) := by decide
|
theorem eq_true_imp_eq_false : ∀(b:Bool), (b = true → b = false) ↔ (b = false) := by decide
|
||||||
|
|
||||||
|
/-! ### forall -/
|
||||||
|
|
||||||
|
theorem forall_bool' {p : Bool → Prop} (b : Bool) : (∀ x, p x) ↔ p b ∧ p !b :=
|
||||||
|
⟨fun h ↦ ⟨h _, h _⟩, fun ⟨h₁, h₂⟩ x ↦ by cases b <;> cases x <;> assumption⟩
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem forall_bool {p : Bool → Prop} : (∀ b, p b) ↔ p false ∧ p true :=
|
||||||
|
forall_bool' false
|
||||||
|
|
||||||
|
/-! ### exists -/
|
||||||
|
|
||||||
|
theorem exists_bool' {p : Bool → Prop} (b : Bool) : (∃ x, p x) ↔ p b ∨ p !b :=
|
||||||
|
⟨fun ⟨x, hx⟩ ↦ by cases x <;> cases b <;> first | exact .inl ‹_› | exact .inr ‹_›,
|
||||||
|
fun h ↦ by cases h <;> exact ⟨_, ‹_›⟩⟩
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem exists_bool {p : Bool → Prop} : (∃ b, p b) ↔ p false ∨ p true :=
|
||||||
|
exists_bool' false
|
||||||
|
|
||||||
/-! ### cond -/
|
/-! ### cond -/
|
||||||
|
|
||||||
@@ -491,10 +529,24 @@ protected theorem cond_false {α : Type u} {a b : α} : cond false a b = b := co
|
|||||||
@[simp] theorem cond_true_right : ∀(c t : Bool), cond c t true = (!c || t) := by decide
|
@[simp] theorem cond_true_right : ∀(c t : Bool), cond c t true = (!c || t) := by decide
|
||||||
@[simp] theorem cond_false_right : ∀(c t : Bool), cond c t false = ( c && t) := by decide
|
@[simp] theorem cond_false_right : ∀(c t : Bool), cond c t false = ( c && t) := by decide
|
||||||
|
|
||||||
|
-- These restore confluence between the above lemmas and `cond_not`.
|
||||||
|
@[simp] theorem cond_true_not_same : ∀ (c b : Bool), cond c (!c) b = (!c && b) := by decide
|
||||||
|
@[simp] theorem cond_false_not_same : ∀ (c b : Bool), cond c b (!c) = (!c || b) := by decide
|
||||||
|
|
||||||
@[simp] theorem cond_true_same : ∀(c b : Bool), cond c c b = (c || b) := by decide
|
@[simp] theorem cond_true_same : ∀(c b : Bool), cond c c b = (c || b) := by decide
|
||||||
@[simp] theorem cond_false_same : ∀(c b : Bool), cond c b c = (c && b) := by decide
|
@[simp] theorem cond_false_same : ∀(c b : Bool), cond c b c = (c && b) := by decide
|
||||||
|
|
||||||
/-# decidability -/
|
theorem cond_pos {b : Bool} {a a' : α} (h : b = true) : (bif b then a else a') = a := by
|
||||||
|
rw [h, cond_true]
|
||||||
|
|
||||||
|
theorem cond_neg {b : Bool} {a a' : α} (h : b = false) : (bif b then a else a') = a' := by
|
||||||
|
rw [h, cond_false]
|
||||||
|
|
||||||
|
theorem apply_cond (f : α → β) {b : Bool} {a a' : α} :
|
||||||
|
f (bif b then a else a') = bif b then f a else f a' := by
|
||||||
|
cases b <;> simp
|
||||||
|
|
||||||
|
/-! # decidability -/
|
||||||
|
|
||||||
protected theorem decide_coe (b : Bool) [Decidable (b = true)] : decide (b = true) = b := decide_eq_true
|
protected theorem decide_coe (b : Bool) [Decidable (b = true)] : decide (b = true) = b := decide_eq_true
|
||||||
|
|
||||||
@@ -510,6 +562,21 @@ protected theorem decide_coe (b : Bool) [Decidable (b = true)] : decide (b = tru
|
|||||||
decide (p ↔ q) = (decide p == decide q) := by
|
decide (p ↔ q) = (decide p == decide q) := by
|
||||||
cases dp with | _ p => simp [p]
|
cases dp with | _ p => simp [p]
|
||||||
|
|
||||||
|
@[boolToPropSimps]
|
||||||
|
theorem and_eq_decide (p q : Prop) [dpq : Decidable (p ∧ q)] [dp : Decidable p] [dq : Decidable q] :
|
||||||
|
(p && q) = decide (p ∧ q) := by
|
||||||
|
cases dp with | _ p => simp [p]
|
||||||
|
|
||||||
|
@[boolToPropSimps]
|
||||||
|
theorem or_eq_decide (p q : Prop) [dpq : Decidable (p ∨ q)] [dp : Decidable p] [dq : Decidable q] :
|
||||||
|
(p || q) = decide (p ∨ q) := by
|
||||||
|
cases dp with | _ p => simp [p]
|
||||||
|
|
||||||
|
@[boolToPropSimps]
|
||||||
|
theorem decide_beq_decide (p q : Prop) [dpq : Decidable (p ↔ q)] [dp : Decidable p] [dq : Decidable q] :
|
||||||
|
(decide p == decide q) = decide (p ↔ q) := by
|
||||||
|
cases dp with | _ p => simp [p]
|
||||||
|
|
||||||
end Bool
|
end Bool
|
||||||
|
|
||||||
export Bool (cond_eq_if)
|
export Bool (cond_eq_if)
|
||||||
@@ -521,3 +588,19 @@ export Bool (cond_eq_if)
|
|||||||
|
|
||||||
@[simp] theorem true_eq_decide_iff {p : Prop} [h : Decidable p] : true = decide p ↔ p := by
|
@[simp] theorem true_eq_decide_iff {p : Prop} [h : Decidable p] : true = decide p ↔ p := by
|
||||||
cases h with | _ q => simp [q]
|
cases h with | _ q => simp [q]
|
||||||
|
|
||||||
|
/-! ### coercions -/
|
||||||
|
|
||||||
|
/--
|
||||||
|
This should not be turned on globally as an instance because it degrades performance in Mathlib,
|
||||||
|
but may be used locally.
|
||||||
|
-/
|
||||||
|
def boolPredToPred : Coe (α → Bool) (α → Prop) where
|
||||||
|
coe r := fun a => Eq (r a) true
|
||||||
|
|
||||||
|
/--
|
||||||
|
This should not be turned on globally as an instance because it degrades performance in Mathlib,
|
||||||
|
but may be used locally.
|
||||||
|
-/
|
||||||
|
def boolRelToRel : Coe (α → α → Bool) (α → α → Prop) where
|
||||||
|
coe r := fun a b => Eq (r a b) true
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ def push : ByteArray → UInt8 → ByteArray
|
|||||||
def size : (@& ByteArray) → Nat
|
def size : (@& ByteArray) → Nat
|
||||||
| ⟨bs⟩ => bs.size
|
| ⟨bs⟩ => bs.size
|
||||||
|
|
||||||
|
@[extern "lean_sarray_size", simp]
|
||||||
|
def usize (a : @& ByteArray) : USize :=
|
||||||
|
a.size.toUSize
|
||||||
|
|
||||||
@[extern "lean_byte_array_uget"]
|
@[extern "lean_byte_array_uget"]
|
||||||
def uget : (a : @& ByteArray) → (i : USize) → i.toNat < a.size → UInt8
|
def uget : (a : @& ByteArray) → (i : USize) → i.toNat < a.size → UInt8
|
||||||
| ⟨bs⟩, i, h => bs[i]
|
| ⟨bs⟩, i, h => bs[i]
|
||||||
@@ -52,13 +56,9 @@ def get : (a : @& ByteArray) → (@& Fin a.size) → UInt8
|
|||||||
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
||||||
getElem xs i h := xs.get ⟨i, h⟩
|
getElem xs i h := xs.get ⟨i, h⟩
|
||||||
|
|
||||||
instance : LawfulGetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
|
|
||||||
|
|
||||||
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
||||||
getElem xs i h := xs.uget i h
|
getElem xs i h := xs.uget i h
|
||||||
|
|
||||||
instance : LawfulGetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
|
|
||||||
|
|
||||||
@[extern "lean_byte_array_set"]
|
@[extern "lean_byte_array_set"]
|
||||||
def set! : ByteArray → (@& Nat) → UInt8 → ByteArray
|
def set! : ByteArray → (@& Nat) → UInt8 → ByteArray
|
||||||
| ⟨bs⟩, i, b => ⟨bs.set! i b⟩
|
| ⟨bs⟩, i, b => ⟨bs.set! i b⟩
|
||||||
@@ -96,20 +96,24 @@ protected def append (a : ByteArray) (b : ByteArray) : ByteArray :=
|
|||||||
|
|
||||||
instance : Append ByteArray := ⟨ByteArray.append⟩
|
instance : Append ByteArray := ⟨ByteArray.append⟩
|
||||||
|
|
||||||
partial def toList (bs : ByteArray) : List UInt8 :=
|
def toList (bs : ByteArray) : List UInt8 :=
|
||||||
let rec loop (i : Nat) (r : List UInt8) :=
|
let rec loop (i : Nat) (r : List UInt8) :=
|
||||||
if i < bs.size then
|
if i < bs.size then
|
||||||
loop (i+1) (bs.get! i :: r)
|
loop (i+1) (bs.get! i :: r)
|
||||||
else
|
else
|
||||||
r.reverse
|
r.reverse
|
||||||
|
termination_by bs.size - i
|
||||||
|
decreasing_by decreasing_trivial_pre_omega
|
||||||
loop 0 []
|
loop 0 []
|
||||||
|
|
||||||
@[inline] partial def findIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option Nat :=
|
@[inline] def findIdx? (a : ByteArray) (p : UInt8 → Bool) (start := 0) : Option Nat :=
|
||||||
let rec @[specialize] loop (i : Nat) :=
|
let rec @[specialize] loop (i : Nat) :=
|
||||||
if i < a.size then
|
if i < a.size then
|
||||||
if p (a.get! i) then some i else loop (i+1)
|
if p (a.get! i) then some i else loop (i+1)
|
||||||
else
|
else
|
||||||
none
|
none
|
||||||
|
termination_by a.size - i
|
||||||
|
decreasing_by decreasing_trivial_pre_omega
|
||||||
loop start
|
loop start
|
||||||
|
|
||||||
/--
|
/--
|
||||||
@@ -119,7 +123,7 @@ partial def toList (bs : ByteArray) : List UInt8 :=
|
|||||||
TODO: avoid code duplication in the future after we improve the compiler.
|
TODO: avoid code duplication in the future after we improve the compiler.
|
||||||
-/
|
-/
|
||||||
@[inline] unsafe def forInUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteArray) (b : β) (f : UInt8 → β → m (ForInStep β)) : m β :=
|
@[inline] unsafe def forInUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (as : ByteArray) (b : β) (f : UInt8 → β → m (ForInStep β)) : m β :=
|
||||||
let sz := USize.ofNat as.size
|
let sz := as.usize
|
||||||
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
||||||
if i < sz then
|
if i < sz then
|
||||||
let a := as.uget i lcProof
|
let a := as.uget i lcProof
|
||||||
@@ -187,6 +191,137 @@ def foldlM {β : Type v} {m : Type v → Type w} [Monad m] (f : β → UInt8 →
|
|||||||
def foldl {β : Type v} (f : β → UInt8 → β) (init : β) (as : ByteArray) (start := 0) (stop := as.size) : β :=
|
def foldl {β : Type v} (f : β → UInt8 → β) (init : β) (as : ByteArray) (start := 0) (stop := as.size) : β :=
|
||||||
Id.run <| as.foldlM f init start stop
|
Id.run <| as.foldlM f init start stop
|
||||||
|
|
||||||
|
/-- Iterator over the bytes (`UInt8`) of a `ByteArray`.
|
||||||
|
|
||||||
|
Typically created by `arr.iter`, where `arr` is a `ByteArray`.
|
||||||
|
|
||||||
|
An iterator is *valid* if the position `i` is *valid* for the array `arr`, meaning `0 ≤ i ≤ arr.size`
|
||||||
|
|
||||||
|
Most operations on iterators return arbitrary values if the iterator is not valid. The functions in
|
||||||
|
the `ByteArray.Iterator` API should rule out the creation of invalid iterators, with two exceptions:
|
||||||
|
|
||||||
|
- `Iterator.next iter` is invalid if `iter` is already at the end of the array (`iter.atEnd` is
|
||||||
|
`true`)
|
||||||
|
- `Iterator.forward iter n`/`Iterator.nextn iter n` is invalid if `n` is strictly greater than the
|
||||||
|
number of remaining bytes.
|
||||||
|
-/
|
||||||
|
structure Iterator where
|
||||||
|
/-- The array the iterator is for. -/
|
||||||
|
array : ByteArray
|
||||||
|
/-- The current position.
|
||||||
|
|
||||||
|
This position is not necessarily valid for the array, for instance if one keeps calling
|
||||||
|
`Iterator.next` when `Iterator.atEnd` is true. If the position is not valid, then the
|
||||||
|
current byte is `(default : UInt8)`. -/
|
||||||
|
idx : Nat
|
||||||
|
deriving Inhabited
|
||||||
|
|
||||||
|
/-- Creates an iterator at the beginning of an array. -/
|
||||||
|
def mkIterator (arr : ByteArray) : Iterator :=
|
||||||
|
⟨arr, 0⟩
|
||||||
|
|
||||||
|
@[inherit_doc mkIterator]
|
||||||
|
abbrev iter := mkIterator
|
||||||
|
|
||||||
|
/-- The size of an array iterator is the number of bytes remaining. -/
|
||||||
|
instance : SizeOf Iterator where
|
||||||
|
sizeOf i := i.array.size - i.idx
|
||||||
|
|
||||||
|
theorem Iterator.sizeOf_eq (i : Iterator) : sizeOf i = i.array.size - i.idx :=
|
||||||
|
rfl
|
||||||
|
|
||||||
|
namespace Iterator
|
||||||
|
|
||||||
|
/-- Number of bytes remaining in the iterator. -/
|
||||||
|
def remainingBytes : Iterator → Nat
|
||||||
|
| ⟨arr, i⟩ => arr.size - i
|
||||||
|
|
||||||
|
@[inherit_doc Iterator.idx]
|
||||||
|
def pos := Iterator.idx
|
||||||
|
|
||||||
|
/-- The byte at the current position.
|
||||||
|
|
||||||
|
On an invalid position, returns `(default : UInt8)`. -/
|
||||||
|
@[inline]
|
||||||
|
def curr : Iterator → UInt8
|
||||||
|
| ⟨arr, i⟩ =>
|
||||||
|
if h:i < arr.size then
|
||||||
|
arr[i]'h
|
||||||
|
else
|
||||||
|
default
|
||||||
|
|
||||||
|
/-- Moves the iterator's position forward by one byte, unconditionally.
|
||||||
|
|
||||||
|
It is only valid to call this function if the iterator is not at the end of the array, *i.e.*
|
||||||
|
`Iterator.atEnd` is `false`; otherwise, the resulting iterator will be invalid. -/
|
||||||
|
@[inline]
|
||||||
|
def next : Iterator → Iterator
|
||||||
|
| ⟨arr, i⟩ => ⟨arr, i + 1⟩
|
||||||
|
|
||||||
|
/-- Decreases the iterator's position.
|
||||||
|
|
||||||
|
If the position is zero, this function is the identity. -/
|
||||||
|
@[inline]
|
||||||
|
def prev : Iterator → Iterator
|
||||||
|
| ⟨arr, i⟩ => ⟨arr, i - 1⟩
|
||||||
|
|
||||||
|
/-- True if the iterator is past the array's last byte. -/
|
||||||
|
@[inline]
|
||||||
|
def atEnd : Iterator → Bool
|
||||||
|
| ⟨arr, i⟩ => i ≥ arr.size
|
||||||
|
|
||||||
|
/-- True if the iterator is not past the array's last byte. -/
|
||||||
|
@[inline]
|
||||||
|
def hasNext : Iterator → Bool
|
||||||
|
| ⟨arr, i⟩ => i < arr.size
|
||||||
|
|
||||||
|
/-- The byte at the current position. --/
|
||||||
|
@[inline]
|
||||||
|
def curr' (it : Iterator) (h : it.hasNext) : UInt8 :=
|
||||||
|
match it with
|
||||||
|
| ⟨arr, i⟩ =>
|
||||||
|
have : i < arr.size := by
|
||||||
|
simp only [hasNext, decide_eq_true_eq] at h
|
||||||
|
assumption
|
||||||
|
arr[i]
|
||||||
|
|
||||||
|
/-- Moves the iterator's position forward by one byte. --/
|
||||||
|
@[inline]
|
||||||
|
def next' (it : Iterator) (_h : it.hasNext) : Iterator :=
|
||||||
|
match it with
|
||||||
|
| ⟨arr, i⟩ => ⟨arr, i + 1⟩
|
||||||
|
|
||||||
|
/-- True if the position is not zero. -/
|
||||||
|
@[inline]
|
||||||
|
def hasPrev : Iterator → Bool
|
||||||
|
| ⟨_, i⟩ => i > 0
|
||||||
|
|
||||||
|
/-- Moves the iterator's position to the end of the array.
|
||||||
|
|
||||||
|
Note that `i.toEnd.atEnd` is always `true`. -/
|
||||||
|
@[inline]
|
||||||
|
def toEnd : Iterator → Iterator
|
||||||
|
| ⟨arr, _⟩ => ⟨arr, arr.size⟩
|
||||||
|
|
||||||
|
/-- Moves the iterator's position several bytes forward.
|
||||||
|
|
||||||
|
The resulting iterator is only valid if the number of bytes to skip is less than or equal to
|
||||||
|
the number of bytes left in the iterator. -/
|
||||||
|
@[inline]
|
||||||
|
def forward : Iterator → Nat → Iterator
|
||||||
|
| ⟨arr, i⟩, f => ⟨arr, i + f⟩
|
||||||
|
|
||||||
|
@[inherit_doc forward, inline]
|
||||||
|
def nextn : Iterator → Nat → Iterator := forward
|
||||||
|
|
||||||
|
/-- Moves the iterator's position several bytes back.
|
||||||
|
|
||||||
|
If asked to go back more bytes than available, stops at the beginning of the array. -/
|
||||||
|
@[inline]
|
||||||
|
def prevn : Iterator → Nat → Iterator
|
||||||
|
| ⟨arr, i⟩, f => ⟨arr, i - f⟩
|
||||||
|
|
||||||
|
end Iterator
|
||||||
end ByteArray
|
end ByteArray
|
||||||
|
|
||||||
def List.toByteArray (bs : List UInt8) : ByteArray :=
|
def List.toByteArray (bs : List UInt8) : ByteArray :=
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ Authors: Leonardo de Moura
|
|||||||
-/
|
-/
|
||||||
prelude
|
prelude
|
||||||
import Init.Data.Char.Basic
|
import Init.Data.Char.Basic
|
||||||
|
import Init.Data.Char.Lemmas
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ theorem isValidUInt32 (n : Nat) (h : isValidCharNat n) : n < UInt32.size := by
|
|||||||
apply Nat.lt_trans h₂
|
apply Nat.lt_trans h₂
|
||||||
decide
|
decide
|
||||||
|
|
||||||
theorem isValidChar_of_isValidChar_Nat (n : Nat) (h : isValidCharNat n) : isValidChar (UInt32.ofNat' n (isValidUInt32 n h)) :=
|
theorem isValidChar_of_isValidCharNat (n : Nat) (h : isValidCharNat n) : isValidChar (UInt32.ofNat' n (isValidUInt32 n h)) :=
|
||||||
match h with
|
match h with
|
||||||
| Or.inl h => Or.inl h
|
| Or.inl h => Or.inl h
|
||||||
| Or.inr ⟨h₁, h₂⟩ => Or.inr ⟨h₁, h₂⟩
|
| Or.inr ⟨h₁, h₂⟩ => Or.inr ⟨h₁, h₂⟩
|
||||||
@@ -52,31 +52,38 @@ theorem isValidChar_zero : isValidChar 0 :=
|
|||||||
@[inline] def toNat (c : Char) : Nat :=
|
@[inline] def toNat (c : Char) : Nat :=
|
||||||
c.val.toNat
|
c.val.toNat
|
||||||
|
|
||||||
|
/-- Convert a character into a `UInt8`, by truncating (reducing modulo 256) if necessary. -/
|
||||||
|
@[inline] def toUInt8 (c : Char) : UInt8 :=
|
||||||
|
c.val.toUInt8
|
||||||
|
|
||||||
|
/-- The numbers from 0 to 256 are all valid UTF-8 characters, so we can embed one in the other. -/
|
||||||
|
def ofUInt8 (n : UInt8) : Char := ⟨n.toUInt32, .inl (Nat.lt_trans n.1.2 (by decide))⟩
|
||||||
|
|
||||||
instance : Inhabited Char where
|
instance : Inhabited Char where
|
||||||
default := 'A'
|
default := 'A'
|
||||||
|
|
||||||
/-- Is the character a space (U+0020) a tab (U+0009), a carriage return (U+000D) or a newline (U+000A)? -/
|
/-- Is the character a space (U+0020) a tab (U+0009), a carriage return (U+000D) or a newline (U+000A)? -/
|
||||||
def isWhitespace (c : Char) : Bool :=
|
@[inline] def isWhitespace (c : Char) : Bool :=
|
||||||
c = ' ' || c = '\t' || c = '\r' || c = '\n'
|
c = ' ' || c = '\t' || c = '\r' || c = '\n'
|
||||||
|
|
||||||
/-- Is the character in `ABCDEFGHIJKLMNOPQRSTUVWXYZ`? -/
|
/-- Is the character in `ABCDEFGHIJKLMNOPQRSTUVWXYZ`? -/
|
||||||
def isUpper (c : Char) : Bool :=
|
@[inline] def isUpper (c : Char) : Bool :=
|
||||||
c.val ≥ 65 && c.val ≤ 90
|
c.val ≥ 65 && c.val ≤ 90
|
||||||
|
|
||||||
/-- Is the character in `abcdefghijklmnopqrstuvwxyz`? -/
|
/-- Is the character in `abcdefghijklmnopqrstuvwxyz`? -/
|
||||||
def isLower (c : Char) : Bool :=
|
@[inline] def isLower (c : Char) : Bool :=
|
||||||
c.val ≥ 97 && c.val ≤ 122
|
c.val ≥ 97 && c.val ≤ 122
|
||||||
|
|
||||||
/-- Is the character in `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`? -/
|
/-- Is the character in `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`? -/
|
||||||
def isAlpha (c : Char) : Bool :=
|
@[inline] def isAlpha (c : Char) : Bool :=
|
||||||
c.isUpper || c.isLower
|
c.isUpper || c.isLower
|
||||||
|
|
||||||
/-- Is the character in `0123456789`? -/
|
/-- Is the character in `0123456789`? -/
|
||||||
def isDigit (c : Char) : Bool :=
|
@[inline] def isDigit (c : Char) : Bool :=
|
||||||
c.val ≥ 48 && c.val ≤ 57
|
c.val ≥ 48 && c.val ≤ 57
|
||||||
|
|
||||||
/-- Is the character in `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`? -/
|
/-- Is the character in `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`? -/
|
||||||
def isAlphanum (c : Char) : Bool :=
|
@[inline] def isAlphanum (c : Char) : Bool :=
|
||||||
c.isAlpha || c.isDigit
|
c.isAlpha || c.isDigit
|
||||||
|
|
||||||
/-- Convert an upper case character to its lower case character.
|
/-- Convert an upper case character to its lower case character.
|
||||||
|
|||||||
39
src/Init/Data/Char/Lemmas.lean
Normal file
39
src/Init/Data/Char/Lemmas.lean
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Leonardo de Moura
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.Char.Basic
|
||||||
|
import Init.Data.UInt.Lemmas
|
||||||
|
|
||||||
|
namespace Char
|
||||||
|
|
||||||
|
theorem le_def {a b : Char} : a ≤ b ↔ a.1 ≤ b.1 := .rfl
|
||||||
|
theorem lt_def {a b : Char} : a < b ↔ a.1 < b.1 := .rfl
|
||||||
|
theorem lt_iff_val_lt_val {a b : Char} : a < b ↔ a.val < b.val := Iff.rfl
|
||||||
|
@[simp] protected theorem not_le {a b : Char} : ¬ a ≤ b ↔ b < a := UInt32.not_le
|
||||||
|
@[simp] protected theorem not_lt {a b : Char} : ¬ a < b ↔ b ≤ a := UInt32.not_lt
|
||||||
|
@[simp] protected theorem le_refl (a : Char) : a ≤ a := by simp [le_def]
|
||||||
|
@[simp] protected theorem lt_irrefl (a : Char) : ¬ a < a := by simp
|
||||||
|
protected theorem le_trans {a b c : Char} : a ≤ b → b ≤ c → a ≤ c := UInt32.le_trans
|
||||||
|
protected theorem lt_trans {a b c : Char} : a < b → b < c → a < c := UInt32.lt_trans
|
||||||
|
protected theorem le_total (a b : Char) : a ≤ b ∨ b ≤ a := UInt32.le_total a.1 b.1
|
||||||
|
protected theorem lt_asymm {a b : Char} (h : a < b) : ¬ b < a := UInt32.lt_asymm h
|
||||||
|
protected theorem ne_of_lt {a b : Char} (h : a < b) : a ≠ b := Char.ne_of_val_ne (UInt32.ne_of_lt h)
|
||||||
|
|
||||||
|
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 ∨ c.utf8Size = 2 ∨ c.utf8Size = 3 ∨ c.utf8Size = 4 := by
|
||||||
|
have := c.utf8Size_pos
|
||||||
|
have := c.utf8Size_le_four
|
||||||
|
omega
|
||||||
|
|
||||||
|
@[simp] theorem ofNat_toNat (c : Char) : Char.ofNat c.toNat = c := by
|
||||||
|
rw [Char.ofNat, dif_pos]
|
||||||
|
rfl
|
||||||
|
|
||||||
|
@[ext] protected theorem ext : {a b : Char} → a.val = b.val → a = b
|
||||||
|
| ⟨_,_⟩, ⟨_,_⟩, rfl => rfl
|
||||||
|
|
||||||
|
end Char
|
||||||
|
|
||||||
|
@[deprecated Char.utf8Size (since := "2024-06-04")] abbrev String.csize := Char.utf8Size
|
||||||
@@ -66,7 +66,24 @@ protected def mul : Fin n → Fin n → Fin n
|
|||||||
|
|
||||||
/-- Subtraction modulo `n` -/
|
/-- Subtraction modulo `n` -/
|
||||||
protected def sub : Fin n → Fin n → Fin n
|
protected def sub : Fin n → Fin n → Fin n
|
||||||
| ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + (n - b)) % n, mlt h⟩
|
/-
|
||||||
|
The definition of `Fin.sub` has been updated to improve performance.
|
||||||
|
The right-hand-side of the following `match` was originally
|
||||||
|
```
|
||||||
|
⟨(a + (n - b)) % n, mlt h⟩
|
||||||
|
```
|
||||||
|
This caused significant performance issues when testing definitional equality,
|
||||||
|
such as `x =?= x - 1` where `x : Fin n` and `n` is a big number,
|
||||||
|
as Lean spent a long time reducing
|
||||||
|
```
|
||||||
|
((n - 1) + x.val) % n
|
||||||
|
```
|
||||||
|
For example, this was an issue for `Fin 2^64` (i.e., `UInt64`).
|
||||||
|
This change improves performance by leveraging the fact that `Nat.add` is defined
|
||||||
|
using recursion on the second argument.
|
||||||
|
See issue #4413.
|
||||||
|
-/
|
||||||
|
| ⟨a, h⟩, ⟨b, _⟩ => ⟨((n - b) + a) % n, mlt h⟩
|
||||||
|
|
||||||
/-!
|
/-!
|
||||||
Remark: land/lor can be defined without using (% n), but
|
Remark: land/lor can be defined without using (% n), but
|
||||||
@@ -132,6 +149,9 @@ instance : Inhabited (Fin (no_index (n+1))) where
|
|||||||
|
|
||||||
@[simp] theorem zero_eta : (⟨0, Nat.zero_lt_succ _⟩ : Fin (n + 1)) = 0 := rfl
|
@[simp] theorem zero_eta : (⟨0, Nat.zero_lt_succ _⟩ : Fin (n + 1)) = 0 := rfl
|
||||||
|
|
||||||
|
theorem ne_of_val_ne {i j : Fin n} (h : val i ≠ val j) : i ≠ j :=
|
||||||
|
fun h' => absurd (val_eq_of_eq h') h
|
||||||
|
|
||||||
theorem val_ne_of_ne {i j : Fin n} (h : i ≠ j) : val i ≠ val j :=
|
theorem val_ne_of_ne {i j : Fin n} (h : i ≠ j) : val i ≠ val j :=
|
||||||
fun h' => absurd (eq_of_val_eq h') h
|
fun h' => absurd (eq_of_val_eq h') h
|
||||||
|
|
||||||
@@ -193,4 +213,7 @@ theorem val_add_one_le_of_lt {n : Nat} {a b : Fin n} (h : a < b) : (a : Nat) + 1
|
|||||||
|
|
||||||
theorem val_add_one_le_of_gt {n : Nat} {a b : Fin n} (h : a > b) : (b : Nat) + 1 ≤ (a : Nat) := h
|
theorem val_add_one_le_of_gt {n : Nat} {a b : Fin n} (h : a > b) : (b : Nat) + 1 ≤ (a : Nat) := h
|
||||||
|
|
||||||
|
theorem exists_iff {p : Fin n → Prop} : (Exists fun i => p i) ↔ Exists fun i => Exists fun h => p ⟨i, h⟩ :=
|
||||||
|
⟨fun ⟨⟨i, hi⟩, hpi⟩ => ⟨i, hi, hpi⟩, fun ⟨i, hi, hpi⟩ => ⟨⟨i, hi⟩, hpi⟩⟩
|
||||||
|
|
||||||
end Fin
|
end Fin
|
||||||
|
|||||||
15
src/Init/Data/Fin/Bitwise.lean
Normal file
15
src/Init/Data/Fin/Bitwise.lean
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Markus Himmel
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.Nat.Bitwise
|
||||||
|
import Init.Data.Fin.Basic
|
||||||
|
|
||||||
|
namespace Fin
|
||||||
|
|
||||||
|
@[simp] theorem and_val (a b : Fin n) : (a &&& b).val = a.val &&& b.val :=
|
||||||
|
Nat.mod_eq_of_lt (Nat.lt_of_le_of_lt Nat.and_le_left a.isLt)
|
||||||
|
|
||||||
|
end Fin
|
||||||
@@ -6,6 +6,8 @@ Authors: François G. Dorais
|
|||||||
prelude
|
prelude
|
||||||
import Init.Data.Nat.Linear
|
import Init.Data.Nat.Linear
|
||||||
|
|
||||||
|
namespace Fin
|
||||||
|
|
||||||
/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/
|
/-- Folds over `Fin n` from the left: `foldl 3 f x = f (f (f x 0) 1) 2`. -/
|
||||||
@[inline] def foldl (n) (f : α → Fin n → α) (init : α) : α := loop init 0 where
|
@[inline] def foldl (n) (f : α → Fin n → α) (init : α) : α := loop init 0 where
|
||||||
/-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/
|
/-- Inner loop for `Fin.foldl`. `Fin.foldl.loop n f x i = f (f (f x i) ...) (n-1)` -/
|
||||||
@@ -20,3 +22,5 @@ import Init.Data.Nat.Linear
|
|||||||
loop : {i // i ≤ n} → α → α
|
loop : {i // i ≤ n} → α → α
|
||||||
| ⟨0, _⟩, x => x
|
| ⟨0, _⟩, x => x
|
||||||
| ⟨i+1, h⟩, x => loop ⟨i, Nat.le_of_lt h⟩ (f ⟨i, h⟩ x)
|
| ⟨i+1, h⟩, x => loop ⟨i, Nat.le_of_lt h⟩ (f ⟨i, h⟩ x)
|
||||||
|
|
||||||
|
end Fin
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/-
|
/-
|
||||||
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||||||
Released under Apache 2.0 license as described in the file LICENSE.
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
Authors: Mario Carneiro
|
Authors: Mario Carneiro, Leonardo de Moura
|
||||||
-/
|
-/
|
||||||
prelude
|
prelude
|
||||||
import Init.Data.Fin.Basic
|
import Init.Data.Fin.Basic
|
||||||
@@ -11,9 +11,6 @@ import Init.ByCases
|
|||||||
import Init.Conv
|
import Init.Conv
|
||||||
import Init.Omega
|
import Init.Omega
|
||||||
|
|
||||||
-- Remove after the next stage0 update
|
|
||||||
set_option allowUnsafeReducibility true
|
|
||||||
|
|
||||||
namespace Fin
|
namespace Fin
|
||||||
|
|
||||||
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
|
/-- If you actually have an element of `Fin n`, then the `n` is always positive -/
|
||||||
@@ -24,7 +21,7 @@ theorem mod_def (a m : Fin n) : a % m = Fin.mk (a % m) (Nat.lt_of_le_of_lt (Nat.
|
|||||||
|
|
||||||
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
theorem mul_def (a b : Fin n) : a * b = Fin.mk ((a * b) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||||
|
|
||||||
theorem sub_def (a b : Fin n) : a - b = Fin.mk ((a + (n - b)) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
theorem sub_def (a b : Fin n) : a - b = Fin.mk (((n - b) + a) % n) (Nat.mod_lt _ a.size_pos) := rfl
|
||||||
|
|
||||||
theorem size_pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.size_pos
|
theorem size_pos' : ∀ [Nonempty (Fin n)], 0 < n | ⟨i⟩ => i.size_pos
|
||||||
|
|
||||||
@@ -37,34 +34,26 @@ theorem pos_iff_nonempty {n : Nat} : 0 < n ↔ Nonempty (Fin n) :=
|
|||||||
|
|
||||||
@[simp] protected theorem eta (a : Fin n) (h : a < n) : (⟨a, h⟩ : Fin n) = a := rfl
|
@[simp] protected theorem eta (a : Fin n) (h : a < n) : (⟨a, h⟩ : Fin n) = a := rfl
|
||||||
|
|
||||||
@[ext] theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
|
@[ext] protected theorem ext {a b : Fin n} (h : (a : Nat) = b) : a = b := eq_of_val_eq h
|
||||||
|
|
||||||
theorem ext_iff {a b : Fin n} : a = b ↔ a.1 = b.1 := val_inj.symm
|
|
||||||
|
|
||||||
theorem val_ne_iff {a b : Fin n} : a.1 ≠ b.1 ↔ a ≠ b := not_congr val_inj
|
theorem val_ne_iff {a b : Fin n} : a.1 ≠ b.1 ↔ a ≠ b := not_congr val_inj
|
||||||
|
|
||||||
theorem exists_iff {p : Fin n → Prop} : (∃ i, p i) ↔ ∃ i h, p ⟨i, h⟩ :=
|
|
||||||
⟨fun ⟨⟨i, hi⟩, hpi⟩ => ⟨i, hi, hpi⟩, fun ⟨i, hi, hpi⟩ => ⟨⟨i, hi⟩, hpi⟩⟩
|
|
||||||
|
|
||||||
theorem forall_iff {p : Fin n → Prop} : (∀ i, p i) ↔ ∀ i h, p ⟨i, h⟩ :=
|
theorem forall_iff {p : Fin n → Prop} : (∀ i, p i) ↔ ∀ i h, p ⟨i, h⟩ :=
|
||||||
⟨fun h i hi => h ⟨i, hi⟩, fun h ⟨i, hi⟩ => h i hi⟩
|
⟨fun h i hi => h ⟨i, hi⟩, fun h ⟨i, hi⟩ => h i hi⟩
|
||||||
|
|
||||||
protected theorem mk.inj_iff {n a b : Nat} {ha : a < n} {hb : b < n} :
|
protected theorem mk.inj_iff {n a b : Nat} {ha : a < n} {hb : b < n} :
|
||||||
(⟨a, ha⟩ : Fin n) = ⟨b, hb⟩ ↔ a = b := ext_iff
|
(⟨a, ha⟩ : Fin n) = ⟨b, hb⟩ ↔ a = b := Fin.ext_iff
|
||||||
|
|
||||||
theorem val_mk {m n : Nat} (h : m < n) : (⟨m, h⟩ : Fin n).val = m := rfl
|
theorem val_mk {m n : Nat} (h : m < n) : (⟨m, h⟩ : Fin n).val = m := rfl
|
||||||
|
|
||||||
theorem eq_mk_iff_val_eq {a : Fin n} {k : Nat} {hk : k < n} :
|
theorem eq_mk_iff_val_eq {a : Fin n} {k : Nat} {hk : k < n} :
|
||||||
a = ⟨k, hk⟩ ↔ (a : Nat) = k := ext_iff
|
a = ⟨k, hk⟩ ↔ (a : Nat) = k := Fin.ext_iff
|
||||||
|
|
||||||
theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||||
|
|
||||||
@[simp] theorem val_ofNat' (a : Nat) (is_pos : n > 0) :
|
@[simp] theorem val_ofNat' (a : Nat) (is_pos : n > 0) :
|
||||||
(Fin.ofNat' a is_pos).val = a % n := rfl
|
(Fin.ofNat' a is_pos).val = a % n := rfl
|
||||||
|
|
||||||
@[deprecated ofNat'_zero_val (since := "2024-02-22")]
|
|
||||||
theorem ofNat'_zero_val : (Fin.ofNat' 0 h).val = 0 := Nat.zero_mod _
|
|
||||||
|
|
||||||
@[simp] theorem mod_val (a b : Fin n) : (a % b).val = a.val % b.val :=
|
@[simp] theorem mod_val (a b : Fin n) : (a % b).val = a.val % b.val :=
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
@@ -94,6 +83,18 @@ theorem lt_iff_val_lt_val {a b : Fin n} : a < b ↔ a.val < b.val := Iff.rfl
|
|||||||
|
|
||||||
@[simp] protected theorem not_lt {a b : Fin n} : ¬ a < b ↔ b ≤ a := Nat.not_lt
|
@[simp] protected theorem not_lt {a b : Fin n} : ¬ a < b ↔ b ≤ a := Nat.not_lt
|
||||||
|
|
||||||
|
@[simp] protected theorem le_refl (a : Fin n) : a ≤ a := by simp [le_def]
|
||||||
|
|
||||||
|
@[simp] protected theorem lt_irrefl (a : Fin n) : ¬ a < a := by simp
|
||||||
|
|
||||||
|
protected theorem le_trans {a b c : Fin n} : a ≤ b → b ≤ c → a ≤ c := Nat.le_trans
|
||||||
|
|
||||||
|
protected theorem lt_trans {a b c : Fin n} : a < b → b < c → a < c := Nat.lt_trans
|
||||||
|
|
||||||
|
protected theorem le_total (a b : Fin n) : a ≤ b ∨ b ≤ a := Nat.le_total a b
|
||||||
|
|
||||||
|
protected theorem lt_asymm {a b : Fin n} (h : a < b) : ¬ b < a := Nat.lt_asymm h
|
||||||
|
|
||||||
protected theorem ne_of_lt {a b : Fin n} (h : a < b) : a ≠ b := Fin.ne_of_val_ne (Nat.ne_of_lt h)
|
protected theorem ne_of_lt {a b : Fin n} (h : a < b) : a ≠ b := Fin.ne_of_val_ne (Nat.ne_of_lt h)
|
||||||
|
|
||||||
protected theorem ne_of_gt {a b : Fin n} (h : a < b) : b ≠ a := Fin.ne_of_val_ne (Nat.ne_of_gt h)
|
protected theorem ne_of_gt {a b : Fin n} (h : a < b) : b ≠ a := Fin.ne_of_val_ne (Nat.ne_of_gt h)
|
||||||
@@ -134,9 +135,15 @@ theorem eq_zero_or_eq_succ {n : Nat} : ∀ i : Fin (n + 1), i = 0 ∨ ∃ j : Fi
|
|||||||
theorem eq_succ_of_ne_zero {n : Nat} {i : Fin (n + 1)} (hi : i ≠ 0) : ∃ j : Fin n, i = j.succ :=
|
theorem eq_succ_of_ne_zero {n : Nat} {i : Fin (n + 1)} (hi : i ≠ 0) : ∃ j : Fin n, i = j.succ :=
|
||||||
(eq_zero_or_eq_succ i).resolve_left hi
|
(eq_zero_or_eq_succ i).resolve_left hi
|
||||||
|
|
||||||
|
protected theorem le_antisymm_iff {x y : Fin n} : x = y ↔ x ≤ y ∧ y ≤ x :=
|
||||||
|
Fin.ext_iff.trans Nat.le_antisymm_iff
|
||||||
|
|
||||||
|
protected theorem le_antisymm {x y : Fin n} (h1 : x ≤ y) (h2 : y ≤ x) : x = y :=
|
||||||
|
Fin.le_antisymm_iff.2 ⟨h1, h2⟩
|
||||||
|
|
||||||
@[simp] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
|
@[simp] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
|
||||||
|
|
||||||
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := ext <| by
|
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by
|
||||||
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
rw [val_rev, val_rev, ← Nat.sub_sub, Nat.sub_sub_self (by exact i.2), Nat.add_sub_cancel]
|
||||||
|
|
||||||
@[simp] theorem rev_le_rev {i j : Fin n} : rev i ≤ rev j ↔ j ≤ i := by
|
@[simp] theorem rev_le_rev {i j : Fin n} : rev i ≤ rev j ↔ j ≤ i := by
|
||||||
@@ -162,12 +169,12 @@ theorem le_last (i : Fin (n + 1)) : i ≤ last n := Nat.le_of_lt_succ i.is_lt
|
|||||||
theorem last_pos : (0 : Fin (n + 2)) < last (n + 1) := Nat.succ_pos _
|
theorem last_pos : (0 : Fin (n + 2)) < last (n + 1) := Nat.succ_pos _
|
||||||
|
|
||||||
theorem eq_last_of_not_lt {i : Fin (n + 1)} (h : ¬(i : Nat) < n) : i = last n :=
|
theorem eq_last_of_not_lt {i : Fin (n + 1)} (h : ¬(i : Nat) < n) : i = last n :=
|
||||||
ext <| Nat.le_antisymm (le_last i) (Nat.not_lt.1 h)
|
Fin.ext <| Nat.le_antisymm (le_last i) (Nat.not_lt.1 h)
|
||||||
|
|
||||||
theorem val_lt_last {i : Fin (n + 1)} : i ≠ last n → (i : Nat) < n :=
|
theorem val_lt_last {i : Fin (n + 1)} : i ≠ last n → (i : Nat) < n :=
|
||||||
Decidable.not_imp_comm.1 eq_last_of_not_lt
|
Decidable.not_imp_comm.1 eq_last_of_not_lt
|
||||||
|
|
||||||
@[simp] theorem rev_last (n : Nat) : rev (last n) = 0 := ext <| by simp
|
@[simp] theorem rev_last (n : Nat) : rev (last n) = 0 := Fin.ext <| by simp
|
||||||
|
|
||||||
@[simp] theorem rev_zero (n : Nat) : rev 0 = last n := by
|
@[simp] theorem rev_zero (n : Nat) : rev 0 = last n := by
|
||||||
rw [← rev_rev (last _), rev_last]
|
rw [← rev_rev (last _), rev_last]
|
||||||
@@ -235,11 +242,11 @@ theorem zero_ne_one : (0 : Fin (n + 2)) ≠ 1 := Fin.ne_of_lt one_pos
|
|||||||
@[simp] theorem succ_lt_succ_iff {a b : Fin n} : a.succ < b.succ ↔ a < b := Nat.succ_lt_succ_iff
|
@[simp] theorem succ_lt_succ_iff {a b : Fin n} : a.succ < b.succ ↔ a < b := Nat.succ_lt_succ_iff
|
||||||
|
|
||||||
@[simp] theorem succ_inj {a b : Fin n} : a.succ = b.succ ↔ a = b := by
|
@[simp] theorem succ_inj {a b : Fin n} : a.succ = b.succ ↔ a = b := by
|
||||||
refine ⟨fun h => ext ?_, congrArg _⟩
|
refine ⟨fun h => Fin.ext ?_, congrArg _⟩
|
||||||
apply Nat.le_antisymm <;> exact succ_le_succ_iff.1 (h ▸ Nat.le_refl _)
|
apply Nat.le_antisymm <;> exact succ_le_succ_iff.1 (h ▸ Nat.le_refl _)
|
||||||
|
|
||||||
theorem succ_ne_zero {n} : ∀ k : Fin n, Fin.succ k ≠ 0
|
theorem succ_ne_zero {n} : ∀ k : Fin n, Fin.succ k ≠ 0
|
||||||
| ⟨k, _⟩, heq => Nat.succ_ne_zero k <| ext_iff.1 heq
|
| ⟨k, _⟩, heq => Nat.succ_ne_zero k <| congrArg Fin.val heq
|
||||||
|
|
||||||
@[simp] theorem succ_zero_eq_one : Fin.succ (0 : Fin (n + 1)) = 1 := rfl
|
@[simp] theorem succ_zero_eq_one : Fin.succ (0 : Fin (n + 1)) = 1 := rfl
|
||||||
|
|
||||||
@@ -258,7 +265,7 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
|
|||||||
rw [← succ_zero_eq_one, succ_lt_succ_iff]; exact succ_pos a
|
rw [← succ_zero_eq_one, succ_lt_succ_iff]; exact succ_pos a
|
||||||
|
|
||||||
@[simp] theorem add_one_lt_iff {n : Nat} {k : Fin (n + 2)} : k + 1 < k ↔ k = last _ := by
|
@[simp] theorem add_one_lt_iff {n : Nat} {k : Fin (n + 2)} : k + 1 < k ↔ k = last _ := by
|
||||||
simp only [lt_def, val_add, val_last, ext_iff]
|
simp only [lt_def, val_add, val_last, Fin.ext_iff]
|
||||||
let ⟨k, hk⟩ := k
|
let ⟨k, hk⟩ := k
|
||||||
match Nat.eq_or_lt_of_le (Nat.le_of_lt_succ hk) with
|
match Nat.eq_or_lt_of_le (Nat.le_of_lt_succ hk) with
|
||||||
| .inl h => cases h; simp [Nat.succ_pos]
|
| .inl h => cases h; simp [Nat.succ_pos]
|
||||||
@@ -276,7 +283,7 @@ theorem one_lt_succ_succ (a : Fin n) : (1 : Fin (n + 2)) < a.succ.succ := by
|
|||||||
split <;> simp [*, (Nat.succ_ne_zero _).symm, Nat.ne_of_gt (Nat.lt_succ_self _)]
|
split <;> simp [*, (Nat.succ_ne_zero _).symm, Nat.ne_of_gt (Nat.lt_succ_self _)]
|
||||||
|
|
||||||
@[simp] theorem last_le_iff {n : Nat} {k : Fin (n + 1)} : last n ≤ k ↔ k = last n := by
|
@[simp] theorem last_le_iff {n : Nat} {k : Fin (n + 1)} : last n ≤ k ↔ k = last n := by
|
||||||
rw [ext_iff, Nat.le_antisymm_iff, le_def, and_iff_right (by apply le_last)]
|
rw [Fin.ext_iff, Nat.le_antisymm_iff, le_def, and_iff_right (by apply le_last)]
|
||||||
|
|
||||||
@[simp] theorem lt_add_one_iff {n : Nat} {k : Fin (n + 1)} : k < k + 1 ↔ k < last n := by
|
@[simp] theorem lt_add_one_iff {n : Nat} {k : Fin (n + 1)} : k < k + 1 ↔ k < last n := by
|
||||||
rw [← Decidable.not_iff_not]; simp
|
rw [← Decidable.not_iff_not]; simp
|
||||||
@@ -297,10 +304,10 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
|||||||
@[simp] theorem castLE_mk (i n m : Nat) (hn : i < n) (h : n ≤ m) :
|
@[simp] theorem castLE_mk (i n m : Nat) (hn : i < n) (h : n ≤ m) :
|
||||||
castLE h ⟨i, hn⟩ = ⟨i, Nat.lt_of_lt_of_le hn h⟩ := rfl
|
castLE h ⟨i, hn⟩ = ⟨i, Nat.lt_of_lt_of_le hn h⟩ := rfl
|
||||||
|
|
||||||
@[simp] theorem castLE_zero {n m : Nat} (h : n.succ ≤ m.succ) : castLE h 0 = 0 := by simp [ext_iff]
|
@[simp] theorem castLE_zero {n m : Nat} (h : n.succ ≤ m.succ) : castLE h 0 = 0 := by simp [Fin.ext_iff]
|
||||||
|
|
||||||
@[simp] theorem castLE_succ {m n : Nat} (h : m + 1 ≤ n + 1) (i : Fin m) :
|
@[simp] theorem castLE_succ {m n : Nat} (h : m + 1 ≤ n + 1) (i : Fin m) :
|
||||||
castLE h i.succ = (castLE (Nat.succ_le_succ_iff.mp h) i).succ := by simp [ext_iff]
|
castLE h i.succ = (castLE (Nat.succ_le_succ_iff.mp h) i).succ := by simp [Fin.ext_iff]
|
||||||
|
|
||||||
@[simp] theorem castLE_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) (i : Fin k) :
|
@[simp] theorem castLE_castLE {k m n} (km : k ≤ m) (mn : m ≤ n) (i : Fin k) :
|
||||||
Fin.castLE mn (Fin.castLE km i) = Fin.castLE (Nat.le_trans km mn) i :=
|
Fin.castLE mn (Fin.castLE km i) = Fin.castLE (Nat.le_trans km mn) i :=
|
||||||
@@ -313,7 +320,7 @@ theorem succ_succ_ne_one (a : Fin n) : Fin.succ (Fin.succ a) ≠ 1 :=
|
|||||||
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i := rfl
|
@[simp] theorem coe_cast (h : n = m) (i : Fin n) : (cast h i : Nat) = i := rfl
|
||||||
|
|
||||||
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' :=
|
@[simp] theorem cast_last {n' : Nat} {h : n + 1 = n' + 1} : cast h (last n) = last n' :=
|
||||||
ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
|
Fin.ext (by rw [coe_cast, val_last, val_last, Nat.succ.inj h])
|
||||||
|
|
||||||
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
@[simp] theorem cast_mk (h : n = m) (i : Nat) (hn : i < n) : cast h ⟨i, hn⟩ = ⟨i, h ▸ hn⟩ := rfl
|
||||||
|
|
||||||
@@ -339,7 +346,7 @@ theorem castAdd_lt {m : Nat} (n : Nat) (i : Fin m) : (castAdd n i : Nat) < m :=
|
|||||||
|
|
||||||
/-- For rewriting in the reverse direction, see `Fin.cast_castAdd_left`. -/
|
/-- For rewriting in the reverse direction, see `Fin.cast_castAdd_left`. -/
|
||||||
theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
|
theorem castAdd_cast {n n' : Nat} (m : Nat) (i : Fin n') (h : n' = n) :
|
||||||
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := ext rfl
|
castAdd m (Fin.cast h i) = Fin.cast (congrArg (. + m) h) (castAdd m i) := Fin.ext rfl
|
||||||
|
|
||||||
theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
theorem cast_castAdd_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
||||||
cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) := rfl
|
cast h (castAdd m i) = castAdd m (cast (Nat.add_right_cancel h) i) := rfl
|
||||||
@@ -369,7 +376,7 @@ theorem castSucc_lt_succ (i : Fin n) : Fin.castSucc i < i.succ :=
|
|||||||
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
|
lt_def.2 <| by simp only [coe_castSucc, val_succ, Nat.lt_succ_self]
|
||||||
|
|
||||||
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ Fin.castSucc j ↔ i < j.succ := by
|
theorem le_castSucc_iff {i : Fin (n + 1)} {j : Fin n} : i ≤ Fin.castSucc j ↔ i < j.succ := by
|
||||||
simpa [lt_def, le_def] using Nat.succ_le_succ_iff.symm
|
simpa only [lt_def, le_def] using Nat.add_one_le_add_one_iff.symm
|
||||||
|
|
||||||
theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
||||||
Fin.castSucc i < j ↔ i.succ ≤ j := .rfl
|
Fin.castSucc i < j ↔ i.succ ≤ j := .rfl
|
||||||
@@ -388,7 +395,7 @@ theorem castSucc_lt_iff_succ_le {n : Nat} {i : Fin n} {j : Fin (n + 1)} :
|
|||||||
@[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
|
@[simp] theorem castSucc_lt_castSucc_iff {a b : Fin n} :
|
||||||
Fin.castSucc a < Fin.castSucc b ↔ a < b := .rfl
|
Fin.castSucc a < Fin.castSucc b ↔ a < b := .rfl
|
||||||
|
|
||||||
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b ↔ a = b := by simp [ext_iff]
|
theorem castSucc_inj {a b : Fin n} : castSucc a = castSucc b ↔ a = b := by simp [Fin.ext_iff]
|
||||||
|
|
||||||
theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
|
theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
|
||||||
|
|
||||||
@@ -400,7 +407,7 @@ theorem castSucc_lt_last (a : Fin n) : castSucc a < last n := a.is_lt
|
|||||||
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i := by
|
theorem castSucc_pos {i : Fin (n + 1)} (h : 0 < i) : 0 < castSucc i := by
|
||||||
simpa [lt_def] using h
|
simpa [lt_def] using h
|
||||||
|
|
||||||
@[simp] theorem castSucc_eq_zero_iff (a : Fin (n + 1)) : castSucc a = 0 ↔ a = 0 := by simp [ext_iff]
|
@[simp] theorem castSucc_eq_zero_iff (a : Fin (n + 1)) : castSucc a = 0 ↔ a = 0 := by simp [Fin.ext_iff]
|
||||||
|
|
||||||
theorem castSucc_ne_zero_iff (a : Fin (n + 1)) : castSucc a ≠ 0 ↔ a ≠ 0 :=
|
theorem castSucc_ne_zero_iff (a : Fin (n + 1)) : castSucc a ≠ 0 ↔ a ≠ 0 :=
|
||||||
not_congr <| castSucc_eq_zero_iff a
|
not_congr <| castSucc_eq_zero_iff a
|
||||||
@@ -412,7 +419,7 @@ theorem castSucc_fin_succ (n : Nat) (j : Fin n) :
|
|||||||
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ := by
|
theorem coeSucc_eq_succ {a : Fin n} : castSucc a + 1 = a.succ := by
|
||||||
cases n
|
cases n
|
||||||
· exact a.elim0
|
· exact a.elim0
|
||||||
· simp [ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
· simp [Fin.ext_iff, add_def, Nat.mod_eq_of_lt (Nat.succ_lt_succ a.is_lt)]
|
||||||
|
|
||||||
theorem lt_succ {a : Fin n} : castSucc a < a.succ := by
|
theorem lt_succ {a : Fin n} : castSucc a < a.succ := by
|
||||||
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
|
rw [castSucc, lt_def, coe_castAdd, val_succ]; exact Nat.lt_succ_self a.val
|
||||||
@@ -445,7 +452,7 @@ theorem cast_addNat_left {n n' m : Nat} (i : Fin n') (h : n' + m = n + m) :
|
|||||||
|
|
||||||
@[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
|
@[simp] theorem cast_addNat_right {n m m' : Nat} (i : Fin n) (h : n + m' = n + m) :
|
||||||
cast h (addNat i m') = addNat i m :=
|
cast h (addNat i m') = addNat i m :=
|
||||||
ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
|
Fin.ext <| (congrArg ((· + ·) (i : Nat)) (Nat.add_left_cancel h) : _)
|
||||||
|
|
||||||
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
@[simp] theorem coe_natAdd (n : Nat) {m : Nat} (i : Fin m) : (natAdd n i : Nat) = n + i := rfl
|
||||||
|
|
||||||
@@ -465,7 +472,7 @@ theorem cast_natAdd_right {n n' m : Nat} (i : Fin n') (h : m + n' = m + n) :
|
|||||||
|
|
||||||
@[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
|
@[simp] theorem cast_natAdd_left {n m m' : Nat} (i : Fin n) (h : m' + n = m + n) :
|
||||||
cast h (natAdd m' i) = natAdd m i :=
|
cast h (natAdd m' i) = natAdd m i :=
|
||||||
ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
|
Fin.ext <| (congrArg (· + (i : Nat)) (Nat.add_right_cancel h) : _)
|
||||||
|
|
||||||
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
theorem castAdd_natAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
||||||
castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) := rfl
|
castAdd p (natAdd m i) = cast (Nat.add_assoc ..).symm (natAdd m (castAdd p i)) := rfl
|
||||||
@@ -475,27 +482,27 @@ theorem natAdd_castAdd (p m : Nat) {n : Nat} (i : Fin n) :
|
|||||||
|
|
||||||
theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
|
theorem natAdd_natAdd (m n : Nat) {p : Nat} (i : Fin p) :
|
||||||
natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) :=
|
natAdd m (natAdd n i) = cast (Nat.add_assoc ..) (natAdd (m + n) i) :=
|
||||||
ext <| (Nat.add_assoc ..).symm
|
Fin.ext <| (Nat.add_assoc ..).symm
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
|
theorem cast_natAdd_zero {n n' : Nat} (i : Fin n) (h : 0 + n = n') :
|
||||||
cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i :=
|
cast h (natAdd 0 i) = cast ((Nat.zero_add _).symm.trans h) i :=
|
||||||
ext <| Nat.zero_add _
|
Fin.ext <| Nat.zero_add _
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
|
theorem cast_natAdd (n : Nat) {m : Nat} (i : Fin m) :
|
||||||
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := ext <| Nat.add_comm ..
|
cast (Nat.add_comm ..) (natAdd n i) = addNat i n := Fin.ext <| Nat.add_comm ..
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
|
theorem cast_addNat {n : Nat} (m : Nat) (i : Fin n) :
|
||||||
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := ext <| Nat.add_comm ..
|
cast (Nat.add_comm ..) (addNat i m) = natAdd m i := Fin.ext <| Nat.add_comm ..
|
||||||
|
|
||||||
@[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
|
@[simp] theorem natAdd_last {m n : Nat} : natAdd n (last m) = last (n + m) := rfl
|
||||||
|
|
||||||
theorem natAdd_castSucc {m n : Nat} {i : Fin m} : natAdd n (castSucc i) = castSucc (natAdd n i) :=
|
theorem natAdd_castSucc {m n : Nat} {i : Fin m} : natAdd n (castSucc i) = castSucc (natAdd n i) :=
|
||||||
rfl
|
rfl
|
||||||
|
|
||||||
theorem rev_castAdd (k : Fin n) (m : Nat) : rev (castAdd m k) = addNat (rev k) m := ext <| by
|
theorem rev_castAdd (k : Fin n) (m : Nat) : rev (castAdd m k) = addNat (rev k) m := Fin.ext <| by
|
||||||
rw [val_rev, coe_castAdd, coe_addNat, val_rev, Nat.sub_add_comm (Nat.succ_le_of_lt k.is_lt)]
|
rw [val_rev, coe_castAdd, coe_addNat, val_rev, Nat.sub_add_comm (Nat.succ_le_of_lt k.is_lt)]
|
||||||
|
|
||||||
theorem rev_addNat (k : Fin n) (m : Nat) : rev (addNat k m) = castAdd m (rev k) := by
|
theorem rev_addNat (k : Fin n) (m : Nat) : rev (addNat k m) = castAdd m (rev k) := by
|
||||||
@@ -525,7 +532,7 @@ theorem pred_eq_iff_eq_succ {n : Nat} (i : Fin (n + 1)) (hi : i ≠ 0) (j : Fin
|
|||||||
theorem pred_mk_succ (i : Nat) (h : i < n + 1) :
|
theorem pred_mk_succ (i : Nat) (h : i < n + 1) :
|
||||||
Fin.pred ⟨i + 1, Nat.add_lt_add_right h 1⟩ (ne_of_val_ne (Nat.ne_of_gt (mk_succ_pos i h))) =
|
Fin.pred ⟨i + 1, Nat.add_lt_add_right h 1⟩ (ne_of_val_ne (Nat.ne_of_gt (mk_succ_pos i h))) =
|
||||||
⟨i, h⟩ := by
|
⟨i, h⟩ := by
|
||||||
simp only [ext_iff, coe_pred, Nat.add_sub_cancel]
|
simp only [Fin.ext_iff, coe_pred, Nat.add_sub_cancel]
|
||||||
|
|
||||||
@[simp] theorem pred_mk_succ' (i : Nat) (h₁ : i + 1 < n + 1 + 1) (h₂) :
|
@[simp] theorem pred_mk_succ' (i : Nat) (h₁ : i + 1 < n + 1 + 1) (h₂) :
|
||||||
Fin.pred ⟨i + 1, h₁⟩ h₂ = ⟨i, Nat.lt_of_succ_lt_succ h₁⟩ := pred_mk_succ i _
|
Fin.pred ⟨i + 1, h₁⟩ h₂ = ⟨i, Nat.lt_of_succ_lt_succ h₁⟩ := pred_mk_succ i _
|
||||||
@@ -545,14 +552,14 @@ theorem pred_mk {n : Nat} (i : Nat) (h : i < n + 1) (w) : Fin.pred ⟨i, h⟩ w
|
|||||||
∀ {a b : Fin (n + 1)} {ha : a ≠ 0} {hb : b ≠ 0}, a.pred ha = b.pred hb ↔ a = b
|
∀ {a b : Fin (n + 1)} {ha : a ≠ 0} {hb : b ≠ 0}, a.pred ha = b.pred hb ↔ a = b
|
||||||
| ⟨0, _⟩, _, ha, _ => by simp only [mk_zero, ne_eq, not_true] at ha
|
| ⟨0, _⟩, _, ha, _ => by simp only [mk_zero, ne_eq, not_true] at ha
|
||||||
| ⟨i + 1, _⟩, ⟨0, _⟩, _, hb => by simp only [mk_zero, ne_eq, not_true] at hb
|
| ⟨i + 1, _⟩, ⟨0, _⟩, _, hb => by simp only [mk_zero, ne_eq, not_true] at hb
|
||||||
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [ext_iff, Nat.succ.injEq]
|
| ⟨i + 1, hi⟩, ⟨j + 1, hj⟩, ha, hb => by simp [Fin.ext_iff, Nat.succ.injEq]
|
||||||
|
|
||||||
@[simp] theorem pred_one {n : Nat} :
|
@[simp] theorem pred_one {n : Nat} :
|
||||||
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt one_pos)) = 0 := rfl
|
Fin.pred (1 : Fin (n + 2)) (Ne.symm (Fin.ne_of_lt one_pos)) = 0 := rfl
|
||||||
|
|
||||||
theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
||||||
pred (i + 1) (Fin.ne_of_gt (add_one_pos _ (lt_def.2 h))) = castLT i h := by
|
pred (i + 1) (Fin.ne_of_gt (add_one_pos _ (lt_def.2 h))) = castLT i h := by
|
||||||
rw [ext_iff, coe_pred, coe_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
|
rw [Fin.ext_iff, coe_pred, coe_castLT, val_add, val_one, Nat.mod_eq_of_lt, Nat.add_sub_cancel]
|
||||||
exact Nat.add_lt_add_right h 1
|
exact Nat.add_lt_add_right h 1
|
||||||
|
|
||||||
@[simp] theorem coe_subNat (i : Fin (n + m)) (h : m ≤ i) : (i.subNat m h : Nat) = i - m := rfl
|
@[simp] theorem coe_subNat (i : Fin (n + m)) (h : m ≤ i) : (i.subNat m h : Nat) = i - m := rfl
|
||||||
@@ -564,10 +571,10 @@ theorem pred_add_one (i : Fin (n + 2)) (h : (i : Nat) < n + 1) :
|
|||||||
pred (castSucc i.succ) (Fin.ne_of_gt (castSucc_pos i.succ_pos)) = castSucc i := rfl
|
pred (castSucc i.succ) (Fin.ne_of_gt (castSucc_pos i.succ_pos)) = castSucc i := rfl
|
||||||
|
|
||||||
@[simp] theorem addNat_subNat {i : Fin (n + m)} (h : m ≤ i) : addNat (subNat m i h) m = i :=
|
@[simp] theorem addNat_subNat {i : Fin (n + m)} (h : m ≤ i) : addNat (subNat m i h) m = i :=
|
||||||
ext <| Nat.sub_add_cancel h
|
Fin.ext <| Nat.sub_add_cancel h
|
||||||
|
|
||||||
@[simp] theorem subNat_addNat (i : Fin n) (m : Nat) (h : m ≤ addNat i m := le_coe_addNat m i) :
|
@[simp] theorem subNat_addNat (i : Fin n) (m : Nat) (h : m ≤ addNat i m := le_coe_addNat m i) :
|
||||||
subNat m (addNat i m) h = i := ext <| Nat.add_sub_cancel i m
|
subNat m (addNat i m) h = i := Fin.ext <| Nat.add_sub_cancel i m
|
||||||
|
|
||||||
@[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n ≤ i) :
|
@[simp] theorem natAdd_subNat_cast {i : Fin (n + m)} (h : n ≤ i) :
|
||||||
natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i := by simp [← cast_addNat]; rfl
|
natAdd n (subNat n (cast (Nat.add_comm ..) i) h) = i := by simp [← cast_addNat]; rfl
|
||||||
@@ -750,16 +757,16 @@ theorem addCases_right {m n : Nat} {motive : Fin (m + n) → Sort _} {left right
|
|||||||
|
|
||||||
/-! ### sub -/
|
/-! ### sub -/
|
||||||
|
|
||||||
protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = (a + (n - b)) % n := by
|
protected theorem coe_sub (a b : Fin n) : ((a - b : Fin n) : Nat) = ((n - b) + a) % n := by
|
||||||
cases a; cases b; rfl
|
cases a; cases b; rfl
|
||||||
|
|
||||||
@[simp] theorem ofNat'_sub (x : Nat) (lt : 0 < n) (y : Fin n) :
|
@[simp] theorem ofNat'_sub (x : Nat) (lt : 0 < n) (y : Fin n) :
|
||||||
Fin.ofNat' x lt - y = Fin.ofNat' (x + (n - y.val)) lt := by
|
Fin.ofNat' x lt - y = Fin.ofNat' ((n - y.val) + x) lt := by
|
||||||
apply Fin.eq_of_val_eq
|
apply Fin.eq_of_val_eq
|
||||||
simp [Fin.ofNat', Fin.sub_def]
|
simp [Fin.ofNat', Fin.sub_def]
|
||||||
|
|
||||||
@[simp] theorem sub_ofNat' (x : Fin n) (y : Nat) (lt : 0 < n) :
|
@[simp] theorem sub_ofNat' (x : Fin n) (y : Nat) (lt : 0 < n) :
|
||||||
x - Fin.ofNat' y lt = Fin.ofNat' (x.val + (n - y % n)) lt := by
|
x - Fin.ofNat' y lt = Fin.ofNat' ((n - y % n) + x.val) lt := by
|
||||||
apply Fin.eq_of_val_eq
|
apply Fin.eq_of_val_eq
|
||||||
simp [Fin.ofNat', Fin.sub_def]
|
simp [Fin.ofNat', Fin.sub_def]
|
||||||
|
|
||||||
@@ -770,17 +777,20 @@ private theorem _root_.Nat.mod_eq_sub_of_lt_two_mul {x n} (h₁ : n ≤ x) (h₂
|
|||||||
theorem coe_sub_iff_le {a b : Fin n} : (↑(a - b) : Nat) = a - b ↔ b ≤ a := by
|
theorem coe_sub_iff_le {a b : Fin n} : (↑(a - b) : Nat) = a - b ↔ b ≤ a := by
|
||||||
rw [sub_def, le_def]
|
rw [sub_def, le_def]
|
||||||
dsimp only
|
dsimp only
|
||||||
if h : n ≤ a + (n - b) then
|
if h : n ≤ (n - b) + a then
|
||||||
rw [Nat.mod_eq_sub_of_lt_two_mul h]
|
rw [Nat.mod_eq_sub_of_lt_two_mul h]
|
||||||
all_goals omega
|
all_goals omega
|
||||||
else
|
else
|
||||||
rw [Nat.mod_eq_of_lt]
|
rw [Nat.mod_eq_of_lt]
|
||||||
all_goals omega
|
all_goals omega
|
||||||
|
|
||||||
|
theorem sub_val_of_le {a b : Fin n} : b ≤ a → (a - b).val = a.val - b.val :=
|
||||||
|
coe_sub_iff_le.2
|
||||||
|
|
||||||
theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b := by
|
theorem coe_sub_iff_lt {a b : Fin n} : (↑(a - b) : Nat) = n + a - b ↔ a < b := by
|
||||||
rw [sub_def, lt_def]
|
rw [sub_def, lt_def]
|
||||||
dsimp only
|
dsimp only
|
||||||
if h : n ≤ a + (n - b) then
|
if h : n ≤ (n - b) + a then
|
||||||
rw [Nat.mod_eq_sub_of_lt_two_mul h]
|
rw [Nat.mod_eq_sub_of_lt_two_mul h]
|
||||||
all_goals omega
|
all_goals omega
|
||||||
else
|
else
|
||||||
@@ -798,10 +808,10 @@ theorem coe_mul {n : Nat} : ∀ a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
|
|||||||
protected theorem mul_one (k : Fin (n + 1)) : k * 1 = k := by
|
protected theorem mul_one (k : Fin (n + 1)) : k * 1 = k := by
|
||||||
match n with
|
match n with
|
||||||
| 0 => exact Subsingleton.elim (α := Fin 1) ..
|
| 0 => exact Subsingleton.elim (α := Fin 1) ..
|
||||||
| n+1 => simp [ext_iff, mul_def, Nat.mod_eq_of_lt (is_lt k)]
|
| n+1 => simp [Fin.ext_iff, mul_def, Nat.mod_eq_of_lt (is_lt k)]
|
||||||
|
|
||||||
protected theorem mul_comm (a b : Fin n) : a * b = b * a :=
|
protected theorem mul_comm (a b : Fin n) : a * b = b * a :=
|
||||||
ext <| by rw [mul_def, mul_def, Nat.mul_comm]
|
Fin.ext <| by rw [mul_def, mul_def, Nat.mul_comm]
|
||||||
instance : Std.Commutative (α := Fin n) (· * ·) := ⟨Fin.mul_comm⟩
|
instance : Std.Commutative (α := Fin n) (· * ·) := ⟨Fin.mul_comm⟩
|
||||||
|
|
||||||
protected theorem mul_assoc (a b c : Fin n) : a * b * c = a * (b * c) := by
|
protected theorem mul_assoc (a b c : Fin n) : a * b * c = a * (b * c) := by
|
||||||
@@ -817,33 +827,9 @@ instance : Std.LawfulIdentity (α := Fin (n + 1)) (· * ·) 1 where
|
|||||||
left_id := Fin.one_mul
|
left_id := Fin.one_mul
|
||||||
right_id := Fin.mul_one
|
right_id := Fin.mul_one
|
||||||
|
|
||||||
protected theorem mul_zero (k : Fin (n + 1)) : k * 0 = 0 := by simp [ext_iff, mul_def]
|
protected theorem mul_zero (k : Fin (n + 1)) : k * 0 = 0 := by simp [Fin.ext_iff, mul_def]
|
||||||
|
|
||||||
protected theorem zero_mul (k : Fin (n + 1)) : (0 : Fin (n + 1)) * k = 0 := by
|
protected theorem zero_mul (k : Fin (n + 1)) : (0 : Fin (n + 1)) * k = 0 := by
|
||||||
simp [ext_iff, mul_def]
|
simp [Fin.ext_iff, mul_def]
|
||||||
|
|
||||||
end Fin
|
end Fin
|
||||||
|
|
||||||
namespace USize
|
|
||||||
|
|
||||||
@[simp] theorem lt_def {a b : USize} : a < b ↔ a.toNat < b.toNat := .rfl
|
|
||||||
|
|
||||||
@[simp] theorem le_def {a b : USize} : a ≤ b ↔ a.toNat ≤ b.toNat := .rfl
|
|
||||||
|
|
||||||
@[simp] theorem zero_toNat : (0 : USize).toNat = 0 := Nat.zero_mod _
|
|
||||||
|
|
||||||
@[simp] theorem mod_toNat (a b : USize) : (a % b).toNat = a.toNat % b.toNat :=
|
|
||||||
Fin.mod_val ..
|
|
||||||
|
|
||||||
@[simp] theorem div_toNat (a b : USize) : (a / b).toNat = a.toNat / b.toNat :=
|
|
||||||
Fin.div_val ..
|
|
||||||
|
|
||||||
@[simp] theorem modn_toNat (a : USize) (b : Nat) : (a.modn b).toNat = a.toNat % b :=
|
|
||||||
Fin.modn_val ..
|
|
||||||
|
|
||||||
theorem mod_lt (a b : USize) (h : 0 < b) : a % b < b := USize.modn_lt _ (by simp at h; exact h)
|
|
||||||
|
|
||||||
theorem toNat.inj : ∀ {a b : USize}, a.toNat = b.toNat → a = b
|
|
||||||
| ⟨_, _⟩, ⟨_, _⟩, rfl => rfl
|
|
||||||
|
|
||||||
end USize
|
|
||||||
|
|||||||
@@ -101,13 +101,13 @@ Returns an undefined value if `x` is not finite.
|
|||||||
instance : ToString Float where
|
instance : ToString Float where
|
||||||
toString := Float.toString
|
toString := Float.toString
|
||||||
|
|
||||||
|
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
|
||||||
|
|
||||||
instance : Repr Float where
|
instance : Repr Float where
|
||||||
reprPrec n _ := Float.toString n
|
reprPrec n prec := if n < UInt64.toFloat 0 then Repr.addAppParen (toString n) prec else toString n
|
||||||
|
|
||||||
instance : ReprAtom Float := ⟨⟩
|
instance : ReprAtom Float := ⟨⟩
|
||||||
|
|
||||||
@[extern "lean_uint64_to_float"] opaque UInt64.toFloat (n : UInt64) : Float
|
|
||||||
|
|
||||||
@[extern "sin"] opaque Float.sin : Float → Float
|
@[extern "sin"] opaque Float.sin : Float → Float
|
||||||
@[extern "cos"] opaque Float.cos : Float → Float
|
@[extern "cos"] opaque Float.cos : Float → Float
|
||||||
@[extern "tan"] opaque Float.tan : Float → Float
|
@[extern "tan"] opaque Float.tan : Float → Float
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ def push : FloatArray → Float → FloatArray
|
|||||||
def size : (@& FloatArray) → Nat
|
def size : (@& FloatArray) → Nat
|
||||||
| ⟨ds⟩ => ds.size
|
| ⟨ds⟩ => ds.size
|
||||||
|
|
||||||
|
@[extern "lean_sarray_size", simp]
|
||||||
|
def usize (a : @& FloatArray) : USize :=
|
||||||
|
a.size.toUSize
|
||||||
|
|
||||||
@[extern "lean_float_array_uget"]
|
@[extern "lean_float_array_uget"]
|
||||||
def uget : (a : @& FloatArray) → (i : USize) → i.toNat < a.size → Float
|
def uget : (a : @& FloatArray) → (i : USize) → i.toNat < a.size → Float
|
||||||
| ⟨ds⟩, i, h => ds[i]
|
| ⟨ds⟩, i, h => ds[i]
|
||||||
@@ -58,13 +62,9 @@ def get? (ds : FloatArray) (i : Nat) : Option Float :=
|
|||||||
instance : GetElem FloatArray Nat Float fun xs i => i < xs.size where
|
instance : GetElem FloatArray Nat Float fun xs i => i < xs.size where
|
||||||
getElem xs i h := xs.get ⟨i, h⟩
|
getElem xs i h := xs.get ⟨i, h⟩
|
||||||
|
|
||||||
instance : LawfulGetElem FloatArray Nat Float fun xs i => i < xs.size where
|
|
||||||
|
|
||||||
instance : GetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
instance : GetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
||||||
getElem xs i h := xs.uget i h
|
getElem xs i h := xs.uget i h
|
||||||
|
|
||||||
instance : LawfulGetElem FloatArray USize Float fun xs i => i.val < xs.size where
|
|
||||||
|
|
||||||
@[extern "lean_float_array_uset"]
|
@[extern "lean_float_array_uset"]
|
||||||
def uset : (a : FloatArray) → (i : USize) → Float → i.toNat < a.size → FloatArray
|
def uset : (a : FloatArray) → (i : USize) → Float → i.toNat < a.size → FloatArray
|
||||||
| ⟨ds⟩, i, v, h => ⟨ds.uset i v h⟩
|
| ⟨ds⟩, i, v, h => ⟨ds.uset i v h⟩
|
||||||
@@ -94,7 +94,7 @@ partial def toList (ds : FloatArray) : List Float :=
|
|||||||
-/
|
-/
|
||||||
-- TODO: avoid code duplication in the future after we improve the compiler.
|
-- TODO: avoid code duplication in the future after we improve the compiler.
|
||||||
@[inline] unsafe def forInUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (as : FloatArray) (b : β) (f : Float → β → m (ForInStep β)) : m β :=
|
@[inline] unsafe def forInUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (as : FloatArray) (b : β) (f : Float → β → m (ForInStep β)) : m β :=
|
||||||
let sz := USize.ofNat as.size
|
let sz := as.usize
|
||||||
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
let rec @[specialize] loop (i : USize) (b : β) : m β := do
|
||||||
if i < sz then
|
if i < sz then
|
||||||
let a := as.uget i lcProof
|
let a := as.uget i lcProof
|
||||||
|
|||||||
@@ -20,24 +20,27 @@ private def formatInfo (showInfo : Bool) (info : SourceInfo) (f : Format) : Form
|
|||||||
| true, SourceInfo.synthetic pos endPos false => f!"{pos}:{f}:{endPos}"
|
| true, SourceInfo.synthetic pos endPos false => f!"{pos}:{f}:{endPos}"
|
||||||
| _, _ => f
|
| _, _ => f
|
||||||
|
|
||||||
partial def formatStxAux (maxDepth : Option Nat) (showInfo : Bool) : Nat → Syntax → Format
|
partial def formatStxAux (maxDepth : Option Nat) (showInfo : Bool) (depth : Nat) : Syntax → Format
|
||||||
| _, atom info val => formatInfo showInfo info $ format (repr val)
|
| atom info val => formatInfo showInfo info <| format (repr val)
|
||||||
| _, ident info _ val _ => formatInfo showInfo info $ format "`" ++ format val
|
| ident info _ val _ => formatInfo showInfo info <| format "`" ++ format val
|
||||||
| _, missing => "<missing>"
|
| missing => "<missing>"
|
||||||
| depth, node _ kind args =>
|
| node info kind args =>
|
||||||
let depth := depth + 1;
|
let depth := depth + 1;
|
||||||
if kind == nullKind then
|
if kind == nullKind then
|
||||||
sbracket $
|
sbracket <|
|
||||||
if args.size > 0 && depth > maxDepth.getD depth then
|
if args.size > 0 && depth > maxDepth.getD depth then
|
||||||
".."
|
".."
|
||||||
else
|
else
|
||||||
joinSep (args.toList.map (formatStxAux maxDepth showInfo depth)) line
|
joinSep (args.toList.map (formatStxAux maxDepth showInfo depth)) line
|
||||||
else
|
else
|
||||||
let shorterName := kind.replacePrefix `Lean.Parser Name.anonymous;
|
let shorterName := kind.replacePrefix `Lean.Parser Name.anonymous
|
||||||
let header := format shorterName;
|
let header := formatInfo showInfo info <| format shorterName
|
||||||
let body : List Format :=
|
let body : List Format :=
|
||||||
if args.size > 0 && depth > maxDepth.getD depth then [".."] else args.toList.map (formatStxAux maxDepth showInfo depth);
|
if args.size > 0 && depth > maxDepth.getD depth then
|
||||||
paren $ joinSep (header :: body) line
|
[".."]
|
||||||
|
else
|
||||||
|
args.toList.map (formatStxAux maxDepth showInfo depth)
|
||||||
|
paren <| joinSep (header :: body) line
|
||||||
|
|
||||||
/-- Pretty print the given syntax `stx` as a `Format`.
|
/-- Pretty print the given syntax `stx` as a `Format`.
|
||||||
Nodes deeper than `maxDepth` are omitted.
|
Nodes deeper than `maxDepth` are omitted.
|
||||||
|
|||||||
@@ -62,3 +62,16 @@ instance (P : Prop) : Hashable P where
|
|||||||
/-- An opaque (low-level) hash operation used to implement hashing for pointers. -/
|
/-- An opaque (low-level) hash operation used to implement hashing for pointers. -/
|
||||||
@[always_inline, inline] def hash64 (u : UInt64) : UInt64 :=
|
@[always_inline, inline] def hash64 (u : UInt64) : UInt64 :=
|
||||||
mixHash u 11
|
mixHash u 11
|
||||||
|
|
||||||
|
/-- `LawfulHashable α` says that the `BEq α` and `Hashable α` instances on `α` are compatible, i.e.,
|
||||||
|
that `a == b` implies `hash a = hash b`. This is automatic if the `BEq` instance is lawful.
|
||||||
|
-/
|
||||||
|
class LawfulHashable (α : Type u) [BEq α] [Hashable α] where
|
||||||
|
/-- If `a == b`, then `hash a = hash b`. -/
|
||||||
|
hash_eq (a b : α) : a == b → hash a = hash b
|
||||||
|
|
||||||
|
theorem hash_eq [BEq α] [Hashable α] [LawfulHashable α] {a b : α} : a == b → hash a = hash b :=
|
||||||
|
LawfulHashable.hash_eq a b
|
||||||
|
|
||||||
|
instance (priority := low) [BEq α] [Hashable α] [LawfulBEq α] : LawfulHashable α where
|
||||||
|
hash_eq _ _ h := eq_of_beq h ▸ rfl
|
||||||
|
|||||||
@@ -10,5 +10,6 @@ import Init.Data.Int.DivMod
|
|||||||
import Init.Data.Int.DivModLemmas
|
import Init.Data.Int.DivModLemmas
|
||||||
import Init.Data.Int.Gcd
|
import Init.Data.Int.Gcd
|
||||||
import Init.Data.Int.Lemmas
|
import Init.Data.Int.Lemmas
|
||||||
|
import Init.Data.Int.LemmasAux
|
||||||
import Init.Data.Int.Order
|
import Init.Data.Int.Order
|
||||||
import Init.Data.Int.Pow
|
import Init.Data.Int.Pow
|
||||||
|
|||||||
@@ -322,8 +322,8 @@ protected def pow (m : Int) : Nat → Int
|
|||||||
| 0 => 1
|
| 0 => 1
|
||||||
| succ n => Int.pow m n * m
|
| succ n => Int.pow m n * m
|
||||||
|
|
||||||
instance : HPow Int Nat Int where
|
instance : NatPow Int where
|
||||||
hPow := Int.pow
|
pow := Int.pow
|
||||||
|
|
||||||
instance : LawfulBEq Int where
|
instance : LawfulBEq Int where
|
||||||
eq_of_beq h := by simp [BEq.beq] at h; assumption
|
eq_of_beq h := by simp [BEq.beq] at h; assumption
|
||||||
|
|||||||
37
src/Init/Data/Int/Bitwise/Lemmas.lean
Normal file
37
src/Init/Data/Int/Bitwise/Lemmas.lean
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2023 Siddharth Bhat. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Siddharth Bhat, Jeremy Avigad
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.Nat.Bitwise.Lemmas
|
||||||
|
import Init.Data.Int.Bitwise
|
||||||
|
|
||||||
|
namespace Int
|
||||||
|
|
||||||
|
theorem shiftRight_eq (n : Int) (s : Nat) : n >>> s = Int.shiftRight n s := rfl
|
||||||
|
@[simp]
|
||||||
|
theorem natCast_shiftRight (n s : Nat) : (n : Int) >>> s = n >>> s := rfl
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem negSucc_shiftRight (m n : Nat) :
|
||||||
|
-[m+1] >>> n = -[m >>>n +1] := rfl
|
||||||
|
|
||||||
|
theorem shiftRight_add (i : Int) (m n : Nat) :
|
||||||
|
i >>> (m + n) = i >>> m >>> n := by
|
||||||
|
simp only [shiftRight_eq, Int.shiftRight]
|
||||||
|
cases i <;> simp [Nat.shiftRight_add]
|
||||||
|
|
||||||
|
theorem shiftRight_eq_div_pow (m : Int) (n : Nat) :
|
||||||
|
m >>> n = m / ((2 ^ n) : Nat) := by
|
||||||
|
simp only [shiftRight_eq, Int.shiftRight, Nat.shiftRight_eq_div_pow]
|
||||||
|
split
|
||||||
|
· simp
|
||||||
|
· rw [negSucc_ediv _ (by norm_cast; exact Nat.pow_pos (Nat.zero_lt_two))]
|
||||||
|
rfl
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem zero_shiftRight (n : Nat) : (0 : Int) >>> n = 0 := by
|
||||||
|
simp [Int.shiftRight_eq_div_pow]
|
||||||
|
|
||||||
|
end Int
|
||||||
@@ -14,9 +14,6 @@ import Init.RCases
|
|||||||
# Lemmas about integer division needed to bootstrap `omega`.
|
# Lemmas about integer division needed to bootstrap `omega`.
|
||||||
-/
|
-/
|
||||||
|
|
||||||
-- Remove after the next stage0 update
|
|
||||||
set_option allowUnsafeReducibility true
|
|
||||||
|
|
||||||
open Nat (succ)
|
open Nat (succ)
|
||||||
|
|
||||||
namespace Int
|
namespace Int
|
||||||
@@ -57,7 +54,7 @@ protected theorem dvd_mul_right (a b : Int) : a ∣ a * b := ⟨_, rfl⟩
|
|||||||
|
|
||||||
protected theorem dvd_mul_left (a b : Int) : b ∣ a * b := ⟨_, Int.mul_comm ..⟩
|
protected theorem dvd_mul_left (a b : Int) : b ∣ a * b := ⟨_, Int.mul_comm ..⟩
|
||||||
|
|
||||||
protected theorem neg_dvd {a b : Int} : -a ∣ b ↔ a ∣ b := by
|
@[simp] protected theorem neg_dvd {a b : Int} : -a ∣ b ↔ a ∣ b := by
|
||||||
constructor <;> exact fun ⟨k, e⟩ =>
|
constructor <;> exact fun ⟨k, e⟩ =>
|
||||||
⟨-k, by simp [e, Int.neg_mul, Int.mul_neg, Int.neg_neg]⟩
|
⟨-k, by simp [e, Int.neg_mul, Int.mul_neg, Int.neg_neg]⟩
|
||||||
|
|
||||||
@@ -357,6 +354,7 @@ theorem add_ediv_of_dvd_left {a b c : Int} (H : c ∣ a) : (a + b) / c = a / c +
|
|||||||
@[simp] theorem mul_ediv_cancel_left (b : Int) (H : a ≠ 0) : (a * b) / a = b :=
|
@[simp] theorem mul_ediv_cancel_left (b : Int) (H : a ≠ 0) : (a * b) / a = b :=
|
||||||
Int.mul_comm .. ▸ Int.mul_ediv_cancel _ H
|
Int.mul_comm .. ▸ Int.mul_ediv_cancel _ H
|
||||||
|
|
||||||
|
|
||||||
theorem div_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : a / b ≥ 0 ↔ a ≥ 0 := by
|
theorem div_nonneg_iff_of_pos {a b : Int} (h : 0 < b) : a / b ≥ 0 ↔ a ≥ 0 := by
|
||||||
rw [Int.div_def]
|
rw [Int.div_def]
|
||||||
match b, h with
|
match b, h with
|
||||||
@@ -420,6 +418,9 @@ theorem negSucc_emod (m : Nat) {b : Int} (bpos : 0 < b) : -[m+1] % b = b - 1 - m
|
|||||||
match b, eq_succ_of_zero_lt bpos with
|
match b, eq_succ_of_zero_lt bpos with
|
||||||
| _, ⟨n, rfl⟩ => rfl
|
| _, ⟨n, rfl⟩ => rfl
|
||||||
|
|
||||||
|
theorem emod_negSucc (m : Nat) (n : Int) :
|
||||||
|
(Int.negSucc m) % n = Int.subNatNat (Int.natAbs n) (Nat.succ (m % Int.natAbs n)) := rfl
|
||||||
|
|
||||||
theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = ↑(m % n) := rfl
|
theorem ofNat_mod_ofNat (m n : Nat) : (m % n : Int) = ↑(m % n) := rfl
|
||||||
|
|
||||||
theorem emod_nonneg : ∀ (a : Int) {b : Int}, b ≠ 0 → 0 ≤ a % b
|
theorem emod_nonneg : ∀ (a : Int) {b : Int}, b ≠ 0 → 0 ≤ a % b
|
||||||
@@ -451,6 +452,12 @@ theorem lt_mul_ediv_self_add {x k : Int} (h : 0 < k) : x < k * (x / k) + k :=
|
|||||||
@[simp] theorem add_mul_emod_self_left (a b c : Int) : (a + b * c) % b = a % b := by
|
@[simp] theorem add_mul_emod_self_left (a b c : Int) : (a + b * c) % b = a % b := by
|
||||||
rw [Int.mul_comm, Int.add_mul_emod_self]
|
rw [Int.mul_comm, Int.add_mul_emod_self]
|
||||||
|
|
||||||
|
@[simp] theorem add_neg_mul_emod_self {a b c : Int} : (a + -(b * c)) % c = a % c := by
|
||||||
|
rw [Int.neg_mul_eq_neg_mul, add_mul_emod_self]
|
||||||
|
|
||||||
|
@[simp] theorem add_neg_mul_emod_self_left {a b c : Int} : (a + -(b * c)) % b = a % b := by
|
||||||
|
rw [Int.neg_mul_eq_mul_neg, add_mul_emod_self_left]
|
||||||
|
|
||||||
@[simp] theorem add_emod_self {a b : Int} : (a + b) % b = a % b := by
|
@[simp] theorem add_emod_self {a b : Int} : (a + b) % b = a % b := by
|
||||||
have := add_mul_emod_self_left a b 1; rwa [Int.mul_one] at this
|
have := add_mul_emod_self_left a b 1; rwa [Int.mul_one] at this
|
||||||
|
|
||||||
@@ -495,9 +502,12 @@ theorem mul_emod (a b n : Int) : (a * b) % n = (a % n) * (b % n) % n := by
|
|||||||
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_emod_self_left,
|
Int.mul_assoc, Int.mul_assoc, ← Int.mul_add n _ _, add_mul_emod_self_left,
|
||||||
← Int.mul_assoc, add_mul_emod_self]
|
← Int.mul_assoc, add_mul_emod_self]
|
||||||
|
|
||||||
@[local simp] theorem emod_self {a : Int} : a % a = 0 := by
|
@[simp] theorem emod_self {a : Int} : a % a = 0 := by
|
||||||
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
|
have := mul_emod_left 1 a; rwa [Int.one_mul] at this
|
||||||
|
|
||||||
|
@[simp] theorem neg_emod_self (a : Int) : -a % a = 0 := by
|
||||||
|
rw [neg_emod, Int.sub_self, zero_emod]
|
||||||
|
|
||||||
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
|
@[simp] theorem emod_emod_of_dvd (n : Int) {m k : Int}
|
||||||
(h : m ∣ k) : (n % k) % m = n % m := by
|
(h : m ∣ k) : (n % k) % m = n % m := by
|
||||||
conv => rhs; rw [← emod_add_ediv n k]
|
conv => rhs; rw [← emod_add_ediv n k]
|
||||||
@@ -593,6 +603,14 @@ theorem emod_eq_zero_of_dvd : ∀ {a b : Int}, a ∣ b → b % a = 0
|
|||||||
theorem dvd_iff_emod_eq_zero (a b : Int) : a ∣ b ↔ b % a = 0 :=
|
theorem dvd_iff_emod_eq_zero (a b : Int) : a ∣ b ↔ b % a = 0 :=
|
||||||
⟨emod_eq_zero_of_dvd, dvd_of_emod_eq_zero⟩
|
⟨emod_eq_zero_of_dvd, dvd_of_emod_eq_zero⟩
|
||||||
|
|
||||||
|
@[simp] theorem neg_mul_emod_left (a b : Int) : -(a * b) % b = 0 := by
|
||||||
|
rw [← dvd_iff_emod_eq_zero, Int.dvd_neg]
|
||||||
|
exact Int.dvd_mul_left a b
|
||||||
|
|
||||||
|
@[simp] theorem neg_mul_emod_right (a b : Int) : -(a * b) % a = 0 := by
|
||||||
|
rw [← dvd_iff_emod_eq_zero, Int.dvd_neg]
|
||||||
|
exact Int.dvd_mul_right a b
|
||||||
|
|
||||||
instance decidableDvd : DecidableRel (α := Int) (· ∣ ·) := fun _ _ =>
|
instance decidableDvd : DecidableRel (α := Int) (· ∣ ·) := fun _ _ =>
|
||||||
decidable_of_decidable_of_iff (dvd_iff_emod_eq_zero ..).symm
|
decidable_of_decidable_of_iff (dvd_iff_emod_eq_zero ..).symm
|
||||||
|
|
||||||
@@ -617,6 +635,12 @@ theorem neg_ediv_of_dvd : ∀ {a b : Int}, b ∣ a → (-a) / b = -(a / b)
|
|||||||
· simp [bz]
|
· simp [bz]
|
||||||
· rw [Int.neg_mul_eq_mul_neg, Int.mul_ediv_cancel_left _ bz, Int.mul_ediv_cancel_left _ bz]
|
· rw [Int.neg_mul_eq_mul_neg, Int.mul_ediv_cancel_left _ bz, Int.mul_ediv_cancel_left _ bz]
|
||||||
|
|
||||||
|
@[simp] theorem neg_mul_ediv_cancel (a b : Int) (h : b ≠ 0) : -(a * b) / b = -a := by
|
||||||
|
rw [neg_ediv_of_dvd (Int.dvd_mul_left a b), mul_ediv_cancel _ h]
|
||||||
|
|
||||||
|
@[simp] theorem neg_mul_ediv_cancel_left (a b : Int) (h : a ≠ 0) : -(a * b) / a = -b := by
|
||||||
|
rw [neg_ediv_of_dvd (Int.dvd_mul_right a b), mul_ediv_cancel_left _ h]
|
||||||
|
|
||||||
theorem sub_ediv_of_dvd (a : Int) {b c : Int}
|
theorem sub_ediv_of_dvd (a : Int) {b c : Int}
|
||||||
(hcb : c ∣ b) : (a - b) / c = a / c - b / c := by
|
(hcb : c ∣ b) : (a - b) / c = a / c - b / c := by
|
||||||
rw [Int.sub_eq_add_neg, Int.sub_eq_add_neg, Int.add_ediv_of_dvd_right (Int.dvd_neg.2 hcb)]
|
rw [Int.sub_eq_add_neg, Int.sub_eq_add_neg, Int.add_ediv_of_dvd_right (Int.dvd_neg.2 hcb)]
|
||||||
@@ -632,13 +656,22 @@ theorem sub_ediv_of_dvd (a : Int) {b c : Int}
|
|||||||
@[simp] protected theorem ediv_self {a : Int} (H : a ≠ 0) : a / a = 1 := by
|
@[simp] protected theorem ediv_self {a : Int} (H : a ≠ 0) : a / a = 1 := by
|
||||||
have := Int.mul_ediv_cancel 1 H; rwa [Int.one_mul] at this
|
have := Int.mul_ediv_cancel 1 H; rwa [Int.one_mul] at this
|
||||||
|
|
||||||
|
@[simp] protected theorem neg_ediv_self (a : Int) (h : a ≠ 0) : (-a) / a = -1 := by
|
||||||
|
rw [neg_ediv_of_dvd (Int.dvd_refl a), Int.ediv_self h]
|
||||||
|
|
||||||
@[simp]
|
@[simp]
|
||||||
theorem Int.emod_sub_cancel (x y : Int): (x - y)%y = x%y := by
|
theorem emod_sub_cancel (x y : Int): (x - y) % y = x % y := by
|
||||||
by_cases h : y = 0
|
by_cases h : y = 0
|
||||||
· simp [h]
|
· simp [h]
|
||||||
· simp only [Int.emod_def, Int.sub_ediv_of_dvd, Int.dvd_refl, Int.ediv_self h, Int.mul_sub]
|
· simp only [Int.emod_def, Int.sub_ediv_of_dvd, Int.dvd_refl, Int.ediv_self h, Int.mul_sub]
|
||||||
simp [Int.mul_one, Int.sub_sub, Int.add_comm y]
|
simp [Int.mul_one, Int.sub_sub, Int.add_comm y]
|
||||||
|
|
||||||
|
@[simp] theorem add_neg_emod_self (a b : Int) : (a + -b) % b = a % b := by
|
||||||
|
rw [← Int.sub_eq_add_neg, emod_sub_cancel]
|
||||||
|
|
||||||
|
@[simp] theorem neg_add_emod_self (a b : Int) : (-a + b) % a = b % a := by
|
||||||
|
rw [Int.add_comm, add_neg_emod_self]
|
||||||
|
|
||||||
/-- If `a % b = c` then `b` divides `a - c`. -/
|
/-- If `a % b = c` then `b` divides `a - c`. -/
|
||||||
theorem dvd_sub_of_emod_eq {a b c : Int} (h : a % b = c) : b ∣ a - c := by
|
theorem dvd_sub_of_emod_eq {a b c : Int} (h : a % b = c) : b ∣ a - c := by
|
||||||
have hx : (a % b) % b = c % b := by
|
have hx : (a % b) % b = c % b := by
|
||||||
@@ -888,6 +921,14 @@ theorem mod_eq_zero_of_dvd : ∀ {a b : Int}, a ∣ b → mod b a = 0
|
|||||||
theorem dvd_iff_mod_eq_zero (a b : Int) : a ∣ b ↔ mod b a = 0 :=
|
theorem dvd_iff_mod_eq_zero (a b : Int) : a ∣ b ↔ mod b a = 0 :=
|
||||||
⟨mod_eq_zero_of_dvd, dvd_of_mod_eq_zero⟩
|
⟨mod_eq_zero_of_dvd, dvd_of_mod_eq_zero⟩
|
||||||
|
|
||||||
|
@[simp] theorem neg_mul_mod_right (a b : Int) : (-(a * b)).mod a = 0 := by
|
||||||
|
rw [← dvd_iff_mod_eq_zero, Int.dvd_neg]
|
||||||
|
exact Int.dvd_mul_right a b
|
||||||
|
|
||||||
|
@[simp] theorem neg_mul_mod_left (a b : Int) : (-(a * b)).mod b = 0 := by
|
||||||
|
rw [← dvd_iff_mod_eq_zero, Int.dvd_neg]
|
||||||
|
exact Int.dvd_mul_left a b
|
||||||
|
|
||||||
protected theorem div_mul_cancel {a b : Int} (H : b ∣ a) : a.div b * b = a :=
|
protected theorem div_mul_cancel {a b : Int} (H : b ∣ a) : a.div b * b = a :=
|
||||||
div_mul_cancel_of_mod_eq_zero (mod_eq_zero_of_dvd H)
|
div_mul_cancel_of_mod_eq_zero (mod_eq_zero_of_dvd H)
|
||||||
|
|
||||||
@@ -900,6 +941,10 @@ protected theorem eq_mul_of_div_eq_right {a b c : Int}
|
|||||||
@[simp] theorem mod_self {a : Int} : a.mod a = 0 := by
|
@[simp] theorem mod_self {a : Int} : a.mod a = 0 := by
|
||||||
have := mul_mod_left 1 a; rwa [Int.one_mul] at this
|
have := mul_mod_left 1 a; rwa [Int.one_mul] at this
|
||||||
|
|
||||||
|
@[simp] theorem neg_mod_self (a : Int) : (-a).mod a = 0 := by
|
||||||
|
rw [← dvd_iff_mod_eq_zero, Int.dvd_neg]
|
||||||
|
exact Int.dvd_refl a
|
||||||
|
|
||||||
theorem lt_div_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.div b + 1) * b := by
|
theorem lt_div_add_one_mul_self (a : Int) {b : Int} (H : 0 < b) : a < (a.div b + 1) * b := by
|
||||||
rw [Int.add_mul, Int.one_mul, Int.mul_comm]
|
rw [Int.add_mul, Int.one_mul, Int.mul_comm]
|
||||||
exact Int.lt_add_of_sub_left_lt <| Int.mod_def .. ▸ mod_lt_of_pos _ H
|
exact Int.lt_add_of_sub_left_lt <| Int.mod_def .. ▸ mod_lt_of_pos _ H
|
||||||
@@ -1072,9 +1117,9 @@ theorem emod_mul_bmod_congr (x : Int) (n : Nat) : Int.bmod (x%n * y) n = Int.bmo
|
|||||||
theorem bmod_add_bmod_congr : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n := by
|
theorem bmod_add_bmod_congr : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n := by
|
||||||
rw [bmod_def x n]
|
rw [bmod_def x n]
|
||||||
split
|
split
|
||||||
case inl p =>
|
next p =>
|
||||||
simp only [emod_add_bmod_congr]
|
simp only [emod_add_bmod_congr]
|
||||||
case inr p =>
|
next p =>
|
||||||
rw [Int.sub_eq_add_neg, Int.add_right_comm, ←Int.sub_eq_add_neg]
|
rw [Int.sub_eq_add_neg, Int.add_right_comm, ←Int.sub_eq_add_neg]
|
||||||
simp
|
simp
|
||||||
|
|
||||||
@@ -1085,11 +1130,10 @@ theorem bmod_add_bmod_congr : Int.bmod (Int.bmod x n + y) n = Int.bmod (x + y) n
|
|||||||
theorem bmod_mul_bmod : Int.bmod (Int.bmod x n * y) n = Int.bmod (x * y) n := by
|
theorem bmod_mul_bmod : Int.bmod (Int.bmod x n * y) n = Int.bmod (x * y) n := by
|
||||||
rw [bmod_def x n]
|
rw [bmod_def x n]
|
||||||
split
|
split
|
||||||
case inl p =>
|
next p =>
|
||||||
simp
|
|
||||||
case inr p =>
|
|
||||||
rw [Int.sub_mul, Int.sub_eq_add_neg, ← Int.mul_neg]
|
|
||||||
simp
|
simp
|
||||||
|
next p =>
|
||||||
|
rw [Int.sub_mul, Int.sub_eq_add_neg, ← Int.mul_neg, bmod_add_mul_cancel, emod_mul_bmod_congr]
|
||||||
|
|
||||||
@[simp] theorem mul_bmod_bmod : Int.bmod (x * Int.bmod y n) n = Int.bmod (x * y) n := by
|
@[simp] theorem mul_bmod_bmod : Int.bmod (x * Int.bmod y n) n = Int.bmod (x * y) n := by
|
||||||
rw [Int.mul_comm x, bmod_mul_bmod, Int.mul_comm x]
|
rw [Int.mul_comm x, bmod_mul_bmod, Int.mul_comm x]
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ prelude
|
|||||||
import Init.Data.Int.Basic
|
import Init.Data.Int.Basic
|
||||||
import Init.Conv
|
import Init.Conv
|
||||||
import Init.NotationExtra
|
import Init.NotationExtra
|
||||||
|
import Init.PropLemmas
|
||||||
|
|
||||||
namespace Int
|
namespace Int
|
||||||
|
|
||||||
@@ -288,7 +289,7 @@ protected theorem neg_sub (a b : Int) : -(a - b) = b - a := by
|
|||||||
protected theorem sub_sub_self (a b : Int) : a - (a - b) = b := by
|
protected theorem sub_sub_self (a b : Int) : a - (a - b) = b := by
|
||||||
simp [Int.sub_eq_add_neg, ← Int.add_assoc]
|
simp [Int.sub_eq_add_neg, ← Int.add_assoc]
|
||||||
|
|
||||||
protected theorem sub_neg (a b : Int) : a - -b = a + b := by simp [Int.sub_eq_add_neg]
|
@[simp] protected theorem sub_neg (a b : Int) : a - -b = a + b := by simp [Int.sub_eq_add_neg]
|
||||||
|
|
||||||
@[simp] protected theorem sub_add_cancel (a b : Int) : a - b + b = a :=
|
@[simp] protected theorem sub_add_cancel (a b : Int) : a - b + b = a :=
|
||||||
Int.neg_add_cancel_right a b
|
Int.neg_add_cancel_right a b
|
||||||
@@ -444,10 +445,10 @@ protected theorem neg_mul_eq_neg_mul (a b : Int) : -(a * b) = -a * b :=
|
|||||||
protected theorem neg_mul_eq_mul_neg (a b : Int) : -(a * b) = a * -b :=
|
protected theorem neg_mul_eq_mul_neg (a b : Int) : -(a * b) = a * -b :=
|
||||||
Int.neg_eq_of_add_eq_zero <| by rw [← Int.mul_add, Int.add_right_neg, Int.mul_zero]
|
Int.neg_eq_of_add_eq_zero <| by rw [← Int.mul_add, Int.add_right_neg, Int.mul_zero]
|
||||||
|
|
||||||
@[local simp] protected theorem neg_mul (a b : Int) : -a * b = -(a * b) :=
|
@[simp] protected theorem neg_mul (a b : Int) : -a * b = -(a * b) :=
|
||||||
(Int.neg_mul_eq_neg_mul a b).symm
|
(Int.neg_mul_eq_neg_mul a b).symm
|
||||||
|
|
||||||
@[local simp] protected theorem mul_neg (a b : Int) : a * -b = -(a * b) :=
|
@[simp] protected theorem mul_neg (a b : Int) : a * -b = -(a * b) :=
|
||||||
(Int.neg_mul_eq_mul_neg a b).symm
|
(Int.neg_mul_eq_mul_neg a b).symm
|
||||||
|
|
||||||
protected theorem neg_mul_neg (a b : Int) : -a * -b = a * b := by simp
|
protected theorem neg_mul_neg (a b : Int) : -a * -b = a * b := by simp
|
||||||
@@ -486,6 +487,9 @@ protected theorem mul_eq_zero {a b : Int} : a * b = 0 ↔ a = 0 ∨ b = 0 := by
|
|||||||
protected theorem mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 :=
|
protected theorem mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 :=
|
||||||
Or.rec a0 b0 ∘ Int.mul_eq_zero.mp
|
Or.rec a0 b0 ∘ Int.mul_eq_zero.mp
|
||||||
|
|
||||||
|
@[simp] protected theorem mul_ne_zero_iff (a b : Int) : a * b ≠ 0 ↔ a ≠ 0 ∧ b ≠ 0 := by
|
||||||
|
rw [ne_eq, Int.mul_eq_zero, not_or, ne_eq]
|
||||||
|
|
||||||
protected theorem eq_of_mul_eq_mul_right {a b c : Int} (ha : a ≠ 0) (h : b * a = c * a) : b = c :=
|
protected theorem eq_of_mul_eq_mul_right {a b c : Int} (ha : a ≠ 0) (h : b * a = c * a) : b = c :=
|
||||||
have : (b - c) * a = 0 := by rwa [Int.sub_mul, Int.sub_eq_zero]
|
have : (b - c) * a = 0 := by rwa [Int.sub_mul, Int.sub_eq_zero]
|
||||||
Int.sub_eq_zero.1 <| (Int.mul_eq_zero.mp this).resolve_right ha
|
Int.sub_eq_zero.1 <| (Int.mul_eq_zero.mp this).resolve_right ha
|
||||||
|
|||||||
40
src/Init/Data/Int/LemmasAux.lean
Normal file
40
src/Init/Data/Int/LemmasAux.lean
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2024 Lean FRO. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Kim Morrison
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.Int.Order
|
||||||
|
import Init.Omega
|
||||||
|
|
||||||
|
|
||||||
|
/-!
|
||||||
|
# Further lemmas about `Int` relying on `omega` automation.
|
||||||
|
-/
|
||||||
|
|
||||||
|
namespace Int
|
||||||
|
|
||||||
|
@[simp] theorem toNat_sub' (a : Int) (b : Nat) : a.toNat - b = (a - b).toNat := by
|
||||||
|
simp only [Int.toNat]
|
||||||
|
split <;> rename_i x a
|
||||||
|
· simp only [Int.ofNat_eq_coe]
|
||||||
|
split <;> rename_i y b h
|
||||||
|
· simp at h
|
||||||
|
omega
|
||||||
|
· simp [Int.negSucc_eq] at h
|
||||||
|
omega
|
||||||
|
· simp only [Nat.zero_sub]
|
||||||
|
split <;> rename_i y b h
|
||||||
|
· simp [Int.negSucc_eq] at h
|
||||||
|
omega
|
||||||
|
· rfl
|
||||||
|
|
||||||
|
@[simp] theorem toNat_sub_max_self (a : Int) : (a - max a 0).toNat = 0 := by
|
||||||
|
simp [toNat]
|
||||||
|
split <;> simp_all <;> omega
|
||||||
|
|
||||||
|
@[simp] theorem toNat_sub_self_max (a : Int) : (a - max 0 a).toNat = 0 := by
|
||||||
|
simp [toNat]
|
||||||
|
split <;> simp_all <;> omega
|
||||||
|
|
||||||
|
end Int
|
||||||
@@ -96,7 +96,7 @@ protected theorem le_antisymm {a b : Int} (h₁ : a ≤ b) (h₂ : b ≤ a) : a
|
|||||||
have := Int.ofNat.inj <| Int.add_left_cancel <| this.trans (Int.add_zero _).symm
|
have := Int.ofNat.inj <| Int.add_left_cancel <| this.trans (Int.add_zero _).symm
|
||||||
rw [← hn, Nat.eq_zero_of_add_eq_zero_left this, ofNat_zero, Int.add_zero a]
|
rw [← hn, Nat.eq_zero_of_add_eq_zero_left this, ofNat_zero, Int.add_zero a]
|
||||||
|
|
||||||
protected theorem lt_irrefl (a : Int) : ¬a < a := fun H =>
|
@[simp] protected theorem lt_irrefl (a : Int) : ¬a < a := fun H =>
|
||||||
let ⟨n, hn⟩ := lt.dest H
|
let ⟨n, hn⟩ := lt.dest H
|
||||||
have : (a+Nat.succ n) = a+0 := by
|
have : (a+Nat.succ n) = a+0 := by
|
||||||
rw [hn, Int.add_zero]
|
rw [hn, Int.add_zero]
|
||||||
@@ -127,9 +127,14 @@ protected theorem lt_iff_le_not_le {a b : Int} : a < b ↔ a ≤ b ∧ ¬b ≤ a
|
|||||||
· exact Int.le_antisymm h h'
|
· exact Int.le_antisymm h h'
|
||||||
· subst h'; apply Int.le_refl
|
· subst h'; apply Int.le_refl
|
||||||
|
|
||||||
|
protected theorem lt_of_not_ge {a b : Int} (h : ¬a ≤ b) : b < a :=
|
||||||
|
Int.lt_iff_le_not_le.mpr ⟨(Int.le_total ..).resolve_right h, h⟩
|
||||||
|
|
||||||
|
protected theorem not_le_of_gt {a b : Int} (h : b < a) : ¬a ≤ b :=
|
||||||
|
(Int.lt_iff_le_not_le.mp h).right
|
||||||
|
|
||||||
protected theorem not_le {a b : Int} : ¬a ≤ b ↔ b < a :=
|
protected theorem not_le {a b : Int} : ¬a ≤ b ↔ b < a :=
|
||||||
⟨fun h => Int.lt_iff_le_not_le.2 ⟨(Int.le_total ..).resolve_right h, h⟩,
|
Iff.intro Int.lt_of_not_ge Int.not_le_of_gt
|
||||||
fun h => (Int.lt_iff_le_not_le.1 h).2⟩
|
|
||||||
|
|
||||||
protected theorem not_lt {a b : Int} : ¬a < b ↔ b ≤ a :=
|
protected theorem not_lt {a b : Int} : ¬a < b ↔ b ≤ a :=
|
||||||
by rw [← Int.not_le, Decidable.not_not]
|
by rw [← Int.not_le, Decidable.not_not]
|
||||||
@@ -235,9 +240,24 @@ theorem le_natAbs {a : Int} : a ≤ natAbs a :=
|
|||||||
theorem negSucc_lt_zero (n : Nat) : -[n+1] < 0 :=
|
theorem negSucc_lt_zero (n : Nat) : -[n+1] < 0 :=
|
||||||
Int.not_le.1 fun h => let ⟨_, h⟩ := eq_ofNat_of_zero_le h; nomatch h
|
Int.not_le.1 fun h => let ⟨_, h⟩ := eq_ofNat_of_zero_le h; nomatch h
|
||||||
|
|
||||||
|
theorem negSucc_le_zero (n : Nat) : -[n+1] ≤ 0 :=
|
||||||
|
Int.le_of_lt (negSucc_lt_zero n)
|
||||||
|
|
||||||
@[simp] theorem negSucc_not_nonneg (n : Nat) : 0 ≤ -[n+1] ↔ False := by
|
@[simp] theorem negSucc_not_nonneg (n : Nat) : 0 ≤ -[n+1] ↔ False := by
|
||||||
simp only [Int.not_le, iff_false]; exact Int.negSucc_lt_zero n
|
simp only [Int.not_le, iff_false]; exact Int.negSucc_lt_zero n
|
||||||
|
|
||||||
|
@[simp] theorem ofNat_max_zero (n : Nat) : (max (n : Int) 0) = n := by
|
||||||
|
rw [Int.max_eq_left (ofNat_zero_le n)]
|
||||||
|
|
||||||
|
@[simp] theorem zero_max_ofNat (n : Nat) : (max 0 (n : Int)) = n := by
|
||||||
|
rw [Int.max_eq_right (ofNat_zero_le n)]
|
||||||
|
|
||||||
|
@[simp] theorem negSucc_max_zero (n : Nat) : (max (Int.negSucc n) 0) = 0 := by
|
||||||
|
rw [Int.max_eq_right (negSucc_le_zero _)]
|
||||||
|
|
||||||
|
@[simp] theorem zero_max_negSucc (n : Nat) : (max 0 (Int.negSucc n)) = 0 := by
|
||||||
|
rw [Int.max_eq_left (negSucc_le_zero _)]
|
||||||
|
|
||||||
protected theorem add_le_add_left {a b : Int} (h : a ≤ b) (c : Int) : c + a ≤ c + b :=
|
protected theorem add_le_add_left {a b : Int} (h : a ≤ b) (c : Int) : c + a ≤ c + b :=
|
||||||
let ⟨n, hn⟩ := le.dest h; le.intro n <| by rw [Int.add_assoc, hn]
|
let ⟨n, hn⟩ := le.dest h; le.intro n <| by rw [Int.add_assoc, hn]
|
||||||
|
|
||||||
@@ -465,8 +485,16 @@ theorem toNat_eq_max : ∀ a : Int, (toNat a : Int) = max a 0
|
|||||||
|
|
||||||
@[simp] theorem toNat_ofNat (n : Nat) : toNat ↑n = n := rfl
|
@[simp] theorem toNat_ofNat (n : Nat) : toNat ↑n = n := rfl
|
||||||
|
|
||||||
|
@[simp] theorem toNat_negSucc (n : Nat) : (Int.negSucc n).toNat = 0 := by
|
||||||
|
simp [toNat]
|
||||||
|
|
||||||
@[simp] theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
|
@[simp] theorem toNat_ofNat_add_one {n : Nat} : ((n : Int) + 1).toNat = n + 1 := rfl
|
||||||
|
|
||||||
|
@[simp] theorem ofNat_toNat (a : Int) : (a.toNat : Int) = max a 0 := by
|
||||||
|
match a with
|
||||||
|
| Int.ofNat n => simp
|
||||||
|
| Int.negSucc n => simp
|
||||||
|
|
||||||
theorem self_le_toNat (a : Int) : a ≤ toNat a := by rw [toNat_eq_max]; apply Int.le_max_left
|
theorem self_le_toNat (a : Int) : a ≤ toNat a := by rw [toNat_eq_max]; apply Int.le_max_left
|
||||||
|
|
||||||
@[simp] theorem le_toNat {n : Nat} {z : Int} (h : 0 ≤ z) : n ≤ z.toNat ↔ (n : Int) ≤ z := by
|
@[simp] theorem le_toNat {n : Nat} {z : Int} (h : 0 ≤ z) : n ≤ z.toNat ↔ (n : Int) ≤ z := by
|
||||||
@@ -509,9 +537,6 @@ theorem mem_toNat' : ∀ (a : Int) (n : Nat), toNat' a = some n ↔ a = n
|
|||||||
|
|
||||||
/-! ## Order properties of the integers -/
|
/-! ## Order properties of the integers -/
|
||||||
|
|
||||||
protected theorem lt_of_not_ge {a b : Int} : ¬a ≤ b → b < a := Int.not_le.mp
|
|
||||||
protected theorem not_le_of_gt {a b : Int} : b < a → ¬a ≤ b := Int.not_le.mpr
|
|
||||||
|
|
||||||
protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_total a b).resolve_left
|
protected theorem le_of_not_le {a b : Int} : ¬ a ≤ b → b ≤ a := (Int.le_total a b).resolve_left
|
||||||
|
|
||||||
@[simp] theorem negSucc_not_pos (n : Nat) : 0 < -[n+1] ↔ False := by
|
@[simp] theorem negSucc_not_pos (n : Nat) : 0 < -[n+1] ↔ False := by
|
||||||
@@ -586,7 +611,10 @@ theorem add_one_le_iff {a b : Int} : a + 1 ≤ b ↔ a < b := .rfl
|
|||||||
theorem lt_add_one_iff {a b : Int} : a < b + 1 ↔ a ≤ b := Int.add_le_add_iff_right _
|
theorem lt_add_one_iff {a b : Int} : a < b + 1 ↔ a ≤ b := Int.add_le_add_iff_right _
|
||||||
|
|
||||||
@[simp] theorem succ_ofNat_pos (n : Nat) : 0 < (n : Int) + 1 :=
|
@[simp] theorem succ_ofNat_pos (n : Nat) : 0 < (n : Int) + 1 :=
|
||||||
lt_add_one_iff.2 (ofNat_zero_le _)
|
lt_add_one_iff.mpr (ofNat_zero_le _)
|
||||||
|
|
||||||
|
theorem not_ofNat_neg (n : Nat) : ¬((n : Int) < 0) :=
|
||||||
|
Int.not_lt.mpr (ofNat_zero_le ..)
|
||||||
|
|
||||||
theorem le_add_one {a b : Int} (h : a ≤ b) : a ≤ b + 1 :=
|
theorem le_add_one {a b : Int} (h : a ≤ b) : a ≤ b + 1 :=
|
||||||
Int.le_of_lt (Int.lt_add_one_iff.2 h)
|
Int.le_of_lt (Int.lt_add_one_iff.2 h)
|
||||||
@@ -801,6 +829,12 @@ protected theorem lt_add_of_neg_lt_sub_right {a b c : Int} (h : -b < a - c) : c
|
|||||||
protected theorem neg_lt_sub_right_of_lt_add {a b c : Int} (h : c < a + b) : -b < a - c :=
|
protected theorem neg_lt_sub_right_of_lt_add {a b c : Int} (h : c < a + b) : -b < a - c :=
|
||||||
Int.lt_sub_left_of_add_lt (Int.sub_right_lt_of_lt_add h)
|
Int.lt_sub_left_of_add_lt (Int.sub_right_lt_of_lt_add h)
|
||||||
|
|
||||||
|
protected theorem add_lt_iff (a b c : Int) : a + b < c ↔ a < -b + c := by
|
||||||
|
rw [← Int.add_lt_add_iff_left (-b), Int.add_comm (-b), Int.add_neg_cancel_right]
|
||||||
|
|
||||||
|
protected theorem sub_lt_iff (a b c : Int) : a - b < c ↔ a < c + b :=
|
||||||
|
Iff.intro Int.lt_add_of_sub_right_lt Int.sub_right_lt_of_lt_add
|
||||||
|
|
||||||
protected theorem sub_lt_of_sub_lt {a b c : Int} (h : a - b < c) : a - c < b :=
|
protected theorem sub_lt_of_sub_lt {a b c : Int} (h : a - b < c) : a - c < b :=
|
||||||
Int.sub_left_lt_of_lt_add (Int.lt_add_of_sub_right_lt h)
|
Int.sub_left_lt_of_lt_add (Int.lt_add_of_sub_right_lt h)
|
||||||
|
|
||||||
@@ -813,6 +847,20 @@ protected theorem sub_lt_sub_right {a b : Int} (h : a < b) (c : Int) : a - c < b
|
|||||||
protected theorem sub_lt_sub {a b c d : Int} (hab : a < b) (hcd : c < d) : a - d < b - c :=
|
protected theorem sub_lt_sub {a b c d : Int} (hab : a < b) (hcd : c < d) : a - d < b - c :=
|
||||||
Int.add_lt_add hab (Int.neg_lt_neg hcd)
|
Int.add_lt_add hab (Int.neg_lt_neg hcd)
|
||||||
|
|
||||||
|
protected theorem lt_of_sub_lt_sub_left {a b c : Int} (h : c - a < c - b) : b < a :=
|
||||||
|
Int.lt_of_neg_lt_neg <| Int.lt_of_add_lt_add_left h
|
||||||
|
|
||||||
|
protected theorem lt_of_sub_lt_sub_right {a b c : Int} (h : a - c < b - c) : a < b :=
|
||||||
|
Int.lt_of_add_lt_add_right h
|
||||||
|
|
||||||
|
@[simp] protected theorem sub_lt_sub_left_iff (a b c : Int) :
|
||||||
|
c - a < c - b ↔ b < a :=
|
||||||
|
⟨Int.lt_of_sub_lt_sub_left, (Int.sub_lt_sub_left · c)⟩
|
||||||
|
|
||||||
|
@[simp] protected theorem sub_lt_sub_right_iff (a b c : Int) :
|
||||||
|
a - c < b - c ↔ a < b :=
|
||||||
|
⟨Int.lt_of_sub_lt_sub_right, (Int.sub_lt_sub_right · c)⟩
|
||||||
|
|
||||||
protected theorem sub_lt_sub_of_le_of_lt {a b c d : Int}
|
protected theorem sub_lt_sub_of_le_of_lt {a b c d : Int}
|
||||||
(hab : a ≤ b) (hcd : c < d) : a - d < b - c :=
|
(hab : a ≤ b) (hcd : c < d) : a - d < b - c :=
|
||||||
Int.add_lt_add_of_le_of_lt hab (Int.neg_lt_neg hcd)
|
Int.add_lt_add_of_le_of_lt hab (Int.neg_lt_neg hcd)
|
||||||
@@ -981,7 +1029,7 @@ theorem natAbs_mul_self : ∀ {a : Int}, ↑(natAbs a * natAbs a) = a * a
|
|||||||
theorem eq_nat_or_neg (a : Int) : ∃ n : Nat, a = n ∨ a = -↑n := ⟨_, natAbs_eq a⟩
|
theorem eq_nat_or_neg (a : Int) : ∃ n : Nat, a = n ∨ a = -↑n := ⟨_, natAbs_eq a⟩
|
||||||
|
|
||||||
theorem natAbs_mul_natAbs_eq {a b : Int} {c : Nat}
|
theorem natAbs_mul_natAbs_eq {a b : Int} {c : Nat}
|
||||||
(h : a * b = (c : Int)) : a.natAbs * b.natAbs = c := by rw [← natAbs_mul, h, natAbs]
|
(h : a * b = (c : Int)) : a.natAbs * b.natAbs = c := by rw [← natAbs_mul, h, natAbs.eq_def]
|
||||||
|
|
||||||
@[simp] theorem natAbs_mul_self' (a : Int) : (natAbs a * natAbs a : Int) = a * a := by
|
@[simp] theorem natAbs_mul_self' (a : Int) : (natAbs a * natAbs a : Int) = a * a := by
|
||||||
rw [← Int.ofNat_mul, natAbs_mul_self]
|
rw [← Int.ofNat_mul, natAbs_mul_self]
|
||||||
|
|||||||
@@ -4,9 +4,22 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
|||||||
Authors: Leonardo de Moura
|
Authors: Leonardo de Moura
|
||||||
-/
|
-/
|
||||||
prelude
|
prelude
|
||||||
|
import Init.Data.List.Attach
|
||||||
import Init.Data.List.Basic
|
import Init.Data.List.Basic
|
||||||
import Init.Data.List.BasicAux
|
import Init.Data.List.BasicAux
|
||||||
import Init.Data.List.Control
|
import Init.Data.List.Control
|
||||||
import Init.Data.List.Lemmas
|
import Init.Data.List.Count
|
||||||
|
import Init.Data.List.Erase
|
||||||
|
import Init.Data.List.Find
|
||||||
import Init.Data.List.Impl
|
import Init.Data.List.Impl
|
||||||
|
import Init.Data.List.Lemmas
|
||||||
|
import Init.Data.List.MinMax
|
||||||
|
import Init.Data.List.Monadic
|
||||||
|
import Init.Data.List.Nat
|
||||||
|
import Init.Data.List.Notation
|
||||||
|
import Init.Data.List.Pairwise
|
||||||
|
import Init.Data.List.Sublist
|
||||||
import Init.Data.List.TakeDrop
|
import Init.Data.List.TakeDrop
|
||||||
|
import Init.Data.List.Zip
|
||||||
|
import Init.Data.List.Perm
|
||||||
|
import Init.Data.List.Sort
|
||||||
|
|||||||
272
src/Init/Data/List/Attach.lean
Normal file
272
src/Init/Data/List/Attach.lean
Normal file
@@ -0,0 +1,272 @@
|
|||||||
|
/-
|
||||||
|
Copyright (c) 2023 Mario Carneiro. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
Authors: Mario Carneiro
|
||||||
|
-/
|
||||||
|
prelude
|
||||||
|
import Init.Data.List.Count
|
||||||
|
import Init.Data.Subtype
|
||||||
|
|
||||||
|
namespace List
|
||||||
|
|
||||||
|
/-- `O(n)`. Partial map. If `f : Π a, P a → β` is a partial function defined on
|
||||||
|
`a : α` satisfying `P`, then `pmap f l h` is essentially the same as `map f l`
|
||||||
|
but is defined only when all members of `l` satisfy `P`, using the proof
|
||||||
|
to apply `f`. -/
|
||||||
|
@[simp] def pmap {P : α → Prop} (f : ∀ a, P a → β) : ∀ l : List α, (H : ∀ a ∈ l, P a) → List β
|
||||||
|
| [], _ => []
|
||||||
|
| a :: l, H => f a (forall_mem_cons.1 H).1 :: pmap f l (forall_mem_cons.1 H).2
|
||||||
|
|
||||||
|
/--
|
||||||
|
Unsafe implementation of `attachWith`, taking advantage of the fact that the representation of
|
||||||
|
`List {x // P x}` is the same as the input `List α`.
|
||||||
|
(Someday, the compiler might do this optimization automatically, but until then...)
|
||||||
|
-/
|
||||||
|
@[inline] private unsafe def attachWithImpl
|
||||||
|
(l : List α) (P : α → Prop) (_ : ∀ x ∈ l, P x) : List {x // P x} := unsafeCast l
|
||||||
|
|
||||||
|
/-- `O(1)`. "Attach" a proof `P x` that holds for all the elements of `l` to produce a new list
|
||||||
|
with the same elements but in the type `{x // P x}`. -/
|
||||||
|
@[implemented_by attachWithImpl] def attachWith
|
||||||
|
(l : List α) (P : α → Prop) (H : ∀ x ∈ l, P x) : List {x // P x} := pmap Subtype.mk l H
|
||||||
|
|
||||||
|
/-- `O(1)`. "Attach" the proof that the elements of `l` are in `l` to produce a new list
|
||||||
|
with the same elements but in the type `{x // x ∈ l}`. -/
|
||||||
|
@[inline] def attach (l : List α) : List {x // x ∈ l} := attachWith l _ fun _ => id
|
||||||
|
|
||||||
|
/-- Implementation of `pmap` using the zero-copy version of `attach`. -/
|
||||||
|
@[inline] private def pmapImpl {P : α → Prop} (f : ∀ a, P a → β) (l : List α) (H : ∀ a ∈ l, P a) :
|
||||||
|
List β := (l.attachWith _ H).map fun ⟨x, h'⟩ => f x h'
|
||||||
|
|
||||||
|
@[csimp] private theorem pmap_eq_pmapImpl : @pmap = @pmapImpl := by
|
||||||
|
funext α β p f L h'
|
||||||
|
let rec go : ∀ L' (hL' : ∀ ⦃x⦄, x ∈ L' → p x),
|
||||||
|
pmap f L' hL' = map (fun ⟨x, hx⟩ => f x hx) (pmap Subtype.mk L' hL')
|
||||||
|
| nil, hL' => rfl
|
||||||
|
| cons _ L', hL' => congrArg _ <| go L' fun _ hx => hL' (.tail _ hx)
|
||||||
|
exact go L h'
|
||||||
|
|
||||||
|
@[simp] theorem attach_nil : ([] : List α).attach = [] := rfl
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem pmap_eq_map (p : α → Prop) (f : α → β) (l : List α) (H) :
|
||||||
|
@pmap _ _ p (fun a _ => f a) l H = map f l := by
|
||||||
|
induction l
|
||||||
|
· rfl
|
||||||
|
· simp only [*, pmap, map]
|
||||||
|
|
||||||
|
theorem pmap_congr {p q : α → Prop} {f : ∀ a, p a → β} {g : ∀ a, q a → β} (l : List α) {H₁ H₂}
|
||||||
|
(h : ∀ a ∈ l, ∀ (h₁ h₂), f a h₁ = g a h₂) : pmap f l H₁ = pmap g l H₂ := by
|
||||||
|
induction l with
|
||||||
|
| nil => rfl
|
||||||
|
| cons x l ih => rw [pmap, pmap, h _ (mem_cons_self _ _), ih fun a ha => h a (mem_cons_of_mem _ ha)]
|
||||||
|
|
||||||
|
theorem map_pmap {p : α → Prop} (g : β → γ) (f : ∀ a, p a → β) (l H) :
|
||||||
|
map g (pmap f l H) = pmap (fun a h => g (f a h)) l H := by
|
||||||
|
induction l
|
||||||
|
· rfl
|
||||||
|
· simp only [*, pmap, map]
|
||||||
|
|
||||||
|
theorem pmap_map {p : β → Prop} (g : ∀ b, p b → γ) (f : α → β) (l H) :
|
||||||
|
pmap g (map f l) H = pmap (fun a h => g (f a) h) l fun a h => H _ (mem_map_of_mem _ h) := by
|
||||||
|
induction l
|
||||||
|
· rfl
|
||||||
|
· simp only [*, pmap, map]
|
||||||
|
|
||||||
|
@[simp] theorem attach_cons (x : α) (xs : List α) :
|
||||||
|
(x :: xs).attach = ⟨x, mem_cons_self x xs⟩ :: xs.attach.map fun ⟨y, h⟩ => ⟨y, mem_cons_of_mem x h⟩ := by
|
||||||
|
simp only [attach, attachWith, pmap, map_pmap, cons.injEq, true_and]
|
||||||
|
apply pmap_congr
|
||||||
|
intros a _ m' _
|
||||||
|
rfl
|
||||||
|
|
||||||
|
theorem pmap_eq_map_attach {p : α → Prop} (f : ∀ a, p a → β) (l H) :
|
||||||
|
pmap f l H = l.attach.map fun x => f x.1 (H _ x.2) := by
|
||||||
|
rw [attach, attachWith, map_pmap]; exact pmap_congr l fun _ _ _ _ => rfl
|
||||||
|
|
||||||
|
theorem attach_map_coe (l : List α) (f : α → β) :
|
||||||
|
(l.attach.map fun (i : {i // i ∈ l}) => f i) = l.map f := by
|
||||||
|
rw [attach, attachWith, map_pmap]; exact pmap_eq_map _ _ _ _
|
||||||
|
|
||||||
|
theorem attach_map_val (l : List α) (f : α → β) : (l.attach.map fun i => f i.val) = l.map f :=
|
||||||
|
attach_map_coe _ _
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem attach_map_subtype_val (l : List α) : l.attach.map Subtype.val = l :=
|
||||||
|
(attach_map_coe _ _).trans (List.map_id _)
|
||||||
|
|
||||||
|
theorem countP_attach (l : List α) (p : α → Bool) : l.attach.countP (fun a : {x // x ∈ l} => p a) = l.countP p := by
|
||||||
|
simp only [← Function.comp_apply (g := Subtype.val), ← countP_map, attach_map_subtype_val]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem count_attach [DecidableEq α] (l : List α) (a : {x // x ∈ l}) : l.attach.count a = l.count ↑a :=
|
||||||
|
Eq.trans (countP_congr fun _ _ => by simp [Subtype.ext_iff]) <| countP_attach _ _
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem mem_attach (l : List α) : ∀ x, x ∈ l.attach
|
||||||
|
| ⟨a, h⟩ => by
|
||||||
|
have := mem_map.1 (by rw [attach_map_subtype_val] <;> exact h)
|
||||||
|
rcases this with ⟨⟨_, _⟩, m, rfl⟩
|
||||||
|
exact m
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem mem_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H b} :
|
||||||
|
b ∈ pmap f l H ↔ ∃ (a : _) (h : a ∈ l), f a (H a h) = b := by
|
||||||
|
simp only [pmap_eq_map_attach, mem_map, mem_attach, true_and, Subtype.exists, eq_comm]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem length_pmap {p : α → Prop} {f : ∀ a, p a → β} {l H} : length (pmap f l H) = length l := by
|
||||||
|
induction l
|
||||||
|
· rfl
|
||||||
|
· simp only [*, pmap, length]
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem length_attach (L : List α) : L.attach.length = L.length :=
|
||||||
|
length_pmap
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem pmap_eq_nil {p : α → Prop} {f : ∀ a, p a → β} {l H} : pmap f l H = [] ↔ l = [] := by
|
||||||
|
rw [← length_eq_zero, length_pmap, length_eq_zero]
|
||||||
|
|
||||||
|
theorem pmap_ne_nil {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||||
|
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ [] ↔ xs ≠ [] := by
|
||||||
|
simp
|
||||||
|
|
||||||
|
@[simp]
|
||||||
|
theorem attach_eq_nil (l : List α) : l.attach = [] ↔ l = [] :=
|
||||||
|
pmap_eq_nil
|
||||||
|
|
||||||
|
theorem getElem?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||||
|
(pmap f l h)[n]? = Option.pmap f l[n]? fun x H => h x (getElem?_mem H) := by
|
||||||
|
induction l generalizing n with
|
||||||
|
| nil => simp
|
||||||
|
| cons hd tl hl =>
|
||||||
|
rcases n with ⟨n⟩
|
||||||
|
· simp only [Option.pmap]
|
||||||
|
split <;> simp_all
|
||||||
|
· simp only [hl, pmap, Option.pmap, getElem?_cons_succ]
|
||||||
|
split <;> rename_i h₁ _ <;> split <;> rename_i h₂ _
|
||||||
|
· simp_all
|
||||||
|
· simp at h₂
|
||||||
|
simp_all
|
||||||
|
· simp_all
|
||||||
|
· simp_all
|
||||||
|
|
||||||
|
theorem get?_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) (n : Nat) :
|
||||||
|
get? (pmap f l h) n = Option.pmap f (get? l n) fun x H => h x (get?_mem H) := by
|
||||||
|
simp only [get?_eq_getElem?]
|
||||||
|
simp [getElem?_pmap, h]
|
||||||
|
|
||||||
|
theorem getElem_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {n : Nat}
|
||||||
|
(hn : n < (pmap f l h).length) :
|
||||||
|
(pmap f l h)[n] =
|
||||||
|
f (l[n]'(@length_pmap _ _ p f l h ▸ hn))
|
||||||
|
(h _ (getElem_mem l n (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||||
|
induction l generalizing n with
|
||||||
|
| nil =>
|
||||||
|
simp only [length, pmap] at hn
|
||||||
|
exact absurd hn (Nat.not_lt_of_le n.zero_le)
|
||||||
|
| cons hd tl hl =>
|
||||||
|
cases n
|
||||||
|
· simp
|
||||||
|
· simp [hl]
|
||||||
|
|
||||||
|
theorem get_pmap {p : α → Prop} (f : ∀ a, p a → β) {l : List α} (h : ∀ a ∈ l, p a) {n : Nat}
|
||||||
|
(hn : n < (pmap f l h).length) :
|
||||||
|
get (pmap f l h) ⟨n, hn⟩ =
|
||||||
|
f (get l ⟨n, @length_pmap _ _ p f l h ▸ hn⟩)
|
||||||
|
(h _ (get_mem l n (@length_pmap _ _ p f l h ▸ hn))) := by
|
||||||
|
simp only [get_eq_getElem]
|
||||||
|
simp [getElem_pmap]
|
||||||
|
|
||||||
|
@[simp] theorem head?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||||
|
(H : ∀ (a : α), a ∈ xs → P a) : (xs.pmap f H).head? = xs.attach.head?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||||
|
induction xs with
|
||||||
|
| nil => simp
|
||||||
|
| cons x xs ih =>
|
||||||
|
simp at ih
|
||||||
|
simp [head?_pmap, ih]
|
||||||
|
|
||||||
|
@[simp] theorem head_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||||
|
(H : ∀ (a : α), a ∈ xs → P a) (h : xs.pmap f H ≠ []) :
|
||||||
|
(xs.pmap f H).head h = f (xs.head (by simpa using h)) (H _ (head_mem _)) := by
|
||||||
|
induction xs with
|
||||||
|
| nil => simp at h
|
||||||
|
| cons x xs ih => simp [head_pmap, ih]
|
||||||
|
|
||||||
|
@[simp] theorem pmap_append {p : ι → Prop} (f : ∀ a : ι, p a → α) (l₁ l₂ : List ι)
|
||||||
|
(h : ∀ a ∈ l₁ ++ l₂, p a) :
|
||||||
|
(l₁ ++ l₂).pmap f h =
|
||||||
|
(l₁.pmap f fun a ha => h a (mem_append_left l₂ ha)) ++
|
||||||
|
l₂.pmap f fun a ha => h a (mem_append_right l₁ ha) := by
|
||||||
|
induction l₁ with
|
||||||
|
| nil => rfl
|
||||||
|
| cons _ _ ih =>
|
||||||
|
dsimp only [pmap, cons_append]
|
||||||
|
rw [ih]
|
||||||
|
|
||||||
|
theorem pmap_append' {p : α → Prop} (f : ∀ a : α, p a → β) (l₁ l₂ : List α)
|
||||||
|
(h₁ : ∀ a ∈ l₁, p a) (h₂ : ∀ a ∈ l₂, p a) :
|
||||||
|
((l₁ ++ l₂).pmap f fun a ha => (List.mem_append.1 ha).elim (h₁ a) (h₂ a)) =
|
||||||
|
l₁.pmap f h₁ ++ l₂.pmap f h₂ :=
|
||||||
|
pmap_append f l₁ l₂ _
|
||||||
|
|
||||||
|
@[simp] theorem pmap_reverse {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||||
|
(H : ∀ (a : α), a ∈ xs.reverse → P a) : xs.reverse.pmap f H = (xs.pmap f (fun a h => H a (by simpa using h))).reverse := by
|
||||||
|
induction xs <;> simp_all
|
||||||
|
|
||||||
|
theorem reverse_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||||
|
(H : ∀ (a : α), a ∈ xs → P a) : (xs.pmap f H).reverse = xs.reverse.pmap f (fun a h => H a (by simpa using h)) := by
|
||||||
|
rw [pmap_reverse]
|
||||||
|
|
||||||
|
@[simp] theorem attach_append (xs ys : List α) :
|
||||||
|
(xs ++ ys).attach = xs.attach.map (fun ⟨x, h⟩ => ⟨x, mem_append_of_mem_left ys h⟩) ++
|
||||||
|
ys.attach.map fun ⟨x, h⟩ => ⟨x, mem_append_of_mem_right xs h⟩ := by
|
||||||
|
simp only [attach, attachWith, pmap, map_pmap, pmap_append]
|
||||||
|
congr 1 <;>
|
||||||
|
exact pmap_congr _ fun _ _ _ _ => rfl
|
||||||
|
|
||||||
|
@[simp] theorem attach_reverse (xs : List α) : xs.reverse.attach = xs.attach.reverse.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||||
|
simp only [attach, attachWith, reverse_pmap, map_pmap]
|
||||||
|
apply pmap_congr
|
||||||
|
intros
|
||||||
|
rfl
|
||||||
|
|
||||||
|
theorem reverse_attach (xs : List α) : xs.attach.reverse = xs.reverse.attach.map fun ⟨x, h⟩ => ⟨x, by simpa using h⟩ := by
|
||||||
|
simp only [attach, attachWith, reverse_pmap, map_pmap]
|
||||||
|
apply pmap_congr
|
||||||
|
intros
|
||||||
|
rfl
|
||||||
|
|
||||||
|
|
||||||
|
theorem getLast?_attach {xs : List α} :
|
||||||
|
xs.attach.getLast? = match h : xs.getLast? with | none => none | some a => some ⟨a, mem_of_getLast?_eq_some h⟩ := by
|
||||||
|
rw [getLast?_eq_head?_reverse, reverse_attach, head?_map]
|
||||||
|
split <;> rename_i h
|
||||||
|
· simp only [getLast?_eq_none_iff] at h
|
||||||
|
subst h
|
||||||
|
simp
|
||||||
|
· obtain ⟨ys, rfl⟩ := getLast?_eq_some_iff.mp h
|
||||||
|
simp
|
||||||
|
|
||||||
|
@[simp] theorem getLast?_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||||
|
(H : ∀ (a : α), a ∈ xs → P a) : (xs.pmap f H).getLast? = xs.attach.getLast?.map fun ⟨a, m⟩ => f a (H a m) := by
|
||||||
|
simp only [getLast?_eq_head?_reverse]
|
||||||
|
rw [reverse_pmap, reverse_attach, head?_map, pmap_eq_map_attach, head?_map]
|
||||||
|
simp only [Option.map_map]
|
||||||
|
congr
|
||||||
|
|
||||||
|
@[simp] theorem getLast_pmap {P : α → Prop} (f : (a : α) → P a → β) (xs : List α)
|
||||||
|
(H : ∀ (a : α), a ∈ xs → P a) (h : xs.pmap f H ≠ []) :
|
||||||
|
(xs.pmap f H).getLast h = f (xs.getLast (by simpa using h)) (H _ (getLast_mem _)) := by
|
||||||
|
simp only [getLast_eq_iff_getLast_eq_some, getLast?_pmap, Option.map_eq_some', Subtype.exists]
|
||||||
|
refine ⟨xs.getLast (by simpa using h), by simp, ?_⟩
|
||||||
|
simp only [getLast?_attach, and_true]
|
||||||
|
split <;> rename_i h'
|
||||||
|
· simp only [getLast?_eq_none_iff] at h'
|
||||||
|
subst h'
|
||||||
|
simp at h
|
||||||
|
· symm
|
||||||
|
simpa [getLast_eq_iff_getLast_eq_some]
|
||||||
|
|
||||||
|
end List
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user