mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-05 03:34:08 +00:00
Compare commits
155 Commits
hbv/comput
...
defEq_issu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3b669cdd1 | ||
|
|
1f04bf4fd1 | ||
|
|
03a5db34c7 | ||
|
|
f4bbf748df | ||
|
|
46fe37290e | ||
|
|
dd710dd1bd | ||
|
|
9a841125e7 | ||
|
|
2daaa50afb | ||
|
|
145a121048 | ||
|
|
584d92d302 | ||
|
|
d66aaebca6 | ||
|
|
4ac7ea4aab | ||
|
|
6bebf9c529 | ||
|
|
df74c80973 | ||
|
|
292b423a17 | ||
|
|
cda84702e9 | ||
|
|
ec565f3bf7 | ||
|
|
feea8a7611 | ||
|
|
6d305096e5 | ||
|
|
235b0eb987 | ||
|
|
5dd8d570fd | ||
|
|
3ea59e15b8 | ||
|
|
d59f229b74 | ||
|
|
a364595111 | ||
|
|
08ab8bf7c3 | ||
|
|
54df5173d2 | ||
|
|
36ffba4b57 | ||
|
|
2e9e5db408 | ||
|
|
81a5eb55d5 | ||
|
|
b4f768b67f | ||
|
|
9843794e3f | ||
|
|
9bd4dfb696 | ||
|
|
b1db0d2798 | ||
|
|
4cd7a85334 | ||
|
|
6cf1c4a1be | ||
|
|
e7aa785822 | ||
|
|
668f07039c | ||
|
|
005f6ae7cd | ||
|
|
738688efee | ||
|
|
adf3e5e661 | ||
|
|
38682c4d4a | ||
|
|
f2438a1830 | ||
|
|
48c37f6588 | ||
|
|
8273df0d0b | ||
|
|
f83a8b4cd5 | ||
|
|
fedfc22c53 | ||
|
|
a91fb93eee | ||
|
|
b3b4867d6c | ||
|
|
1e4894b431 | ||
|
|
846420daba | ||
|
|
d88ac25bd1 | ||
|
|
805060c0a8 | ||
|
|
b1a991eee0 | ||
|
|
65a0c61806 | ||
|
|
d4b560ec4a | ||
|
|
7390024170 | ||
|
|
805012fb84 | ||
|
|
dc760cf54a | ||
|
|
08eb78a5b2 | ||
|
|
bd0c6a42c8 | ||
|
|
c86f82161a | ||
|
|
b548cf38b6 | ||
|
|
e96d969d59 | ||
|
|
532310313f | ||
|
|
168c125cf5 | ||
|
|
54be382b2f | ||
|
|
fa31b285df | ||
|
|
1fd9adc693 | ||
|
|
423671a6c0 | ||
|
|
1e0bfe931f | ||
|
|
1bf43863e6 | ||
|
|
87ec768a50 | ||
|
|
de65af8318 | ||
|
|
c032af2f51 | ||
|
|
48a715993d | ||
|
|
f31f50836d | ||
|
|
c1ab1668b2 | ||
|
|
7517f768f9 | ||
|
|
96cd6909ea | ||
|
|
bb8d8da1af | ||
|
|
8916246be5 | ||
|
|
65f112a165 | ||
|
|
75b083d20a | ||
|
|
c595413fcc | ||
|
|
cd7f55b6c9 | ||
|
|
673d1a038c | ||
|
|
66ce282364 | ||
|
|
cdbed919ec | ||
|
|
6d86c8372a | ||
|
|
5c23579f93 | ||
|
|
d0f8eb7bd6 | ||
|
|
65e5053008 | ||
|
|
8f80881c2f | ||
|
|
ed0fd1e933 | ||
|
|
a4d1560aa7 | ||
|
|
e16e2b2ffa | ||
|
|
24380fc900 | ||
|
|
8b04403830 | ||
|
|
8ed6b30084 | ||
|
|
d20b6ece58 | ||
|
|
9ae8fb97b3 | ||
|
|
ebd22c96ee | ||
|
|
71fad35e59 | ||
|
|
7b3d778ab0 | ||
|
|
e7e3588c97 | ||
|
|
aab4d64f25 | ||
|
|
70aa6bc81d | ||
|
|
c03fbddef0 | ||
|
|
93683eb455 | ||
|
|
55a9cb162c | ||
|
|
c2ec2ecab1 | ||
|
|
5115229be2 | ||
|
|
2e7fe7e79d | ||
|
|
4278038940 | ||
|
|
e34c424459 | ||
|
|
527a07b3ad | ||
|
|
13a2a6b4c1 | ||
|
|
5fb480e9f3 | ||
|
|
7b30214e54 | ||
|
|
722813105d | ||
|
|
73751bbb27 | ||
|
|
0520de7374 | ||
|
|
a3e1f82808 | ||
|
|
5c4f61aa26 | ||
|
|
14e1d4328f | ||
|
|
78df48bdf4 | ||
|
|
4fbc5d3c2a | ||
|
|
de522117d7 | ||
|
|
8702861945 | ||
|
|
8cd4c44055 | ||
|
|
43956fc069 | ||
|
|
10770eda3e | ||
|
|
8038a8b890 | ||
|
|
c6f33240de | ||
|
|
ab26eaf647 | ||
|
|
833434cd56 | ||
|
|
cce7507451 | ||
|
|
ace52b38f2 | ||
|
|
9f0b44b260 | ||
|
|
d00131972d | ||
|
|
9aeec35a6a | ||
|
|
d035efbb87 | ||
|
|
953b60c894 | ||
|
|
06f36b61b8 | ||
|
|
012d18744f | ||
|
|
fad343d9ef | ||
|
|
a5f2b78da5 | ||
|
|
cdb4442537 | ||
|
|
ff2a2cd7a1 | ||
|
|
2ce55ba460 | ||
|
|
1f03e32520 | ||
|
|
ae15d787c1 | ||
|
|
6410de4726 | ||
|
|
88ecacea4e | ||
|
|
14c973db4e |
@@ -1,30 +1,28 @@
|
||||
To build Lean you should use `make -j -C build/release`.
|
||||
(In the following, use `sysctl -n hw.logicalcpu` instead of `nproc` on macOS)
|
||||
|
||||
To build Lean you should use `make -j$(nproc) -C build/release`.
|
||||
|
||||
## Running Tests
|
||||
|
||||
See `doc/dev/testing.md` for full documentation. Quick reference:
|
||||
See `tests/README.md` for full documentation. Quick reference:
|
||||
|
||||
```bash
|
||||
# Full test suite (use after builds to verify correctness)
|
||||
make -j -C build/release test ARGS="-j$(nproc)"
|
||||
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
|
||||
make -C build/release -j "$(nproc)" test
|
||||
|
||||
# Specific test by name (supports regex via ctest -R)
|
||||
make -j -C build/release test ARGS='-R grind_ematch --output-on-failure'
|
||||
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
|
||||
make -C build/release -j "$(nproc)" test ARGS='-R grind_ematch'
|
||||
|
||||
# Rerun only previously failed tests
|
||||
make -j -C build/release test ARGS='--rerun-failed --output-on-failure'
|
||||
CTEST_PARALLEL_LEVEL="$(nproc)" CTEST_OUTPUT_ON_FAILURE=1 \
|
||||
make -C build/release -j "$(nproc)" test ARGS='--rerun-failed'
|
||||
|
||||
# Single test from tests/lean/run/ (quick check during development)
|
||||
cd tests/lean/run && ./test_single.sh example_test.lean
|
||||
|
||||
# ctest directly (from stage1 build dir)
|
||||
cd build/release/stage1 && ctest -j$(nproc) --output-on-failure --timeout 300
|
||||
# Single test from tests/foo/bar/ (quick check during development)
|
||||
cd tests/foo/bar && ./run_test example_test.lean
|
||||
```
|
||||
|
||||
The full test suite includes `tests/lean/`, `tests/lean/run/`, `tests/lean/interactive/`,
|
||||
`tests/compiler/`, `tests/pkg/`, Lake tests, and more. Using `make test` or `ctest` runs
|
||||
all of them; `test_single.sh` in `tests/lean/run/` only covers that one directory.
|
||||
|
||||
## New features
|
||||
|
||||
When asked to implement new features:
|
||||
@@ -32,8 +30,6 @@ When asked to implement new features:
|
||||
* write comprehensive tests first (expecting that these will initially fail)
|
||||
* and then iterate on the implementation until the tests pass.
|
||||
|
||||
All new tests should go in `tests/lean/run/`. These tests don't have expected output; we just check there are no errors. You should use `#guard_msgs` to check for specific messages.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
*Never* report success on a task unless you have verified both a clean build without errors, and that the relevant tests pass.
|
||||
@@ -41,7 +37,7 @@ All new tests should go in `tests/lean/run/`. These tests don't have expected ou
|
||||
## Build System Safety
|
||||
|
||||
**NEVER manually delete build directories** (build/, stage0/, stage1/, etc.) even when builds fail.
|
||||
- ONLY use the project's documented build command: `make -j -C build/release`
|
||||
- ONLY use the project's documented build command: `make -j$(nproc) -C build/release`
|
||||
- If a build is broken, ask the user before attempting any manual cleanup
|
||||
|
||||
## LSP and IDE Diagnostics
|
||||
@@ -59,7 +55,7 @@ Follow the commit convention in `doc/dev/commit_convention.md`.
|
||||
**Title format:** `<type>: <subject>` where type is one of: `feat`, `fix`, `doc`, `style`, `refactor`, `test`, `chore`, `perf`.
|
||||
Subject should use imperative present tense ("add" not "added"), no capitalization, no trailing period.
|
||||
|
||||
**Body format:** The first paragraph must start with "This PR". This paragraph is automatically incorporated into release notes. Use imperative present tense. Include motivation and contrast with previous behavior when relevant.
|
||||
**Body format:** The first paragraph must start with "This PR". This paragraph is automatically incorporated into release notes. Use imperative present tense. Include motivation and contrast with previous behavior when relevant. Do NOT use markdown headings (`## Summary`, `## Test plan`, etc.) in PR bodies.
|
||||
|
||||
Example:
|
||||
```
|
||||
|
||||
@@ -121,6 +121,20 @@ The nightly build system uses branches and tags across two repositories:
|
||||
|
||||
When a nightly succeeds with mathlib, all three should point to the same commit. Don't confuse these: branches are in the main lean4 repo, dated tags are in lean4-nightly.
|
||||
|
||||
## Waiting for CI or Merges
|
||||
|
||||
Use `gh pr checks --watch` to block until a PR's CI checks complete (no polling needed).
|
||||
Run these as background bash commands so you get notified when they finish:
|
||||
|
||||
```bash
|
||||
# Watch CI, then check merge state
|
||||
gh pr checks <number> --repo <owner>/<repo> --watch && gh pr view <number> --repo <owner>/<repo> --json state --jq '.state'
|
||||
```
|
||||
|
||||
For multiple PRs, launch one background command per PR in parallel. When each completes,
|
||||
you'll be notified automatically via a task-notification. Do NOT use sleep-based polling
|
||||
loops — `--watch` is event-driven and exits as soon as checks finish.
|
||||
|
||||
## Error Handling
|
||||
|
||||
**CRITICAL**: If something goes wrong or a command fails:
|
||||
|
||||
13
.claude/settings.json
Normal file
13
.claude/settings.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"extraKnownMarketplaces": {
|
||||
"leanprover": {
|
||||
"source": {
|
||||
"source": "github",
|
||||
"repo": "leanprover/skills"
|
||||
}
|
||||
}
|
||||
},
|
||||
"enabledPlugins": {
|
||||
"lean@leanprover": true
|
||||
}
|
||||
}
|
||||
26
.claude/skills/profiling/SKILL.md
Normal file
26
.claude/skills/profiling/SKILL.md
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: profiling
|
||||
description: Profile Lean programs with demangled names using samply and Firefox Profiler. Use when the user asks to profile a Lean binary or investigate performance.
|
||||
allowed-tools: Bash, Read, Glob, Grep
|
||||
---
|
||||
|
||||
# Profiling Lean Programs
|
||||
|
||||
Full documentation: `script/PROFILER_README.md`.
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
script/lean_profile.sh ./build/release/stage1/bin/lean some_file.lean
|
||||
```
|
||||
|
||||
Requires `samply` (`cargo install samply`) and `python3`.
|
||||
|
||||
## Agent Notes
|
||||
|
||||
- The pipeline is interactive (serves to browser at the end). When running non-interactively, run the steps manually instead of using the wrapper script.
|
||||
- The three steps are: `samply record --save-only`, `symbolicate_profile.py`, then `serve_profile.py`.
|
||||
- `lean_demangle.py` works standalone as a stdin filter (like `c++filt`) for quick name lookups.
|
||||
- The `--raw` flag on `lean_demangle.py` gives exact demangled names without postprocessing (keeps `._redArg`, `._lam_0` suffixes as-is).
|
||||
- Use `PROFILE_KEEP=1` to keep the temp directory for later inspection.
|
||||
- The demangled profile is a standard Firefox Profiler JSON. Function names live in `threads[i].stringArray`, indexed by `threads[i].funcTable.name`.
|
||||
17
.claude/skills/zulip-extract/SKILL.md
Normal file
17
.claude/skills/zulip-extract/SKILL.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: zulip-extract
|
||||
description: Extract Zulip thread HTML dumps into readable plain text. Use when the user provides a Zulip HTML file or asks to parse/read/convert/summarize a Zulip thread.
|
||||
---
|
||||
|
||||
# Zulip Thread Extractor
|
||||
|
||||
Run the bundled script to convert a Zulip HTML page dump into plain text.
|
||||
|
||||
## Usage
|
||||
```bash
|
||||
python3 .claude/skills/zulip-extract/zulip_thread_extract.py input.html output.txt
|
||||
```
|
||||
|
||||
The script has zero dependencies beyond Python 3 stdlib.
|
||||
It extracts sender, timestamp, message content (with code blocks,
|
||||
links, quotes, mentions), and reactions.
|
||||
313
.claude/skills/zulip-extract/zulip_thread_extract.py
Normal file
313
.claude/skills/zulip-extract/zulip_thread_extract.py
Normal file
@@ -0,0 +1,313 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Convert a Zulip HTML page dump to plain text (the visible message thread).
|
||||
|
||||
Zero external dependencies — uses only the Python standard library.
|
||||
|
||||
Usage:
|
||||
python3 zulip_thread_extract.py input.html [output.txt]
|
||||
"""
|
||||
|
||||
import sys
|
||||
import re
|
||||
from html.parser import HTMLParser
|
||||
from html import unescape
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Minimal DOM built from stdlib HTMLParser
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class Node:
|
||||
"""A lightweight DOM node."""
|
||||
__slots__ = ('tag', 'attrs', 'children', 'parent', 'text')
|
||||
|
||||
def __init__(self, tag='', attrs=None):
|
||||
self.tag = tag
|
||||
self.attrs = dict(attrs) if attrs else {}
|
||||
self.children = []
|
||||
self.parent = None
|
||||
self.text = '' # for text nodes only (tag == '')
|
||||
|
||||
@property
|
||||
def cls(self):
|
||||
return self.attrs.get('class', '')
|
||||
|
||||
def has_class(self, c):
|
||||
return c in self.cls.split()
|
||||
|
||||
def find_all(self, tag=None, class_=None):
|
||||
"""Depth-first search for matching descendants."""
|
||||
for child in self.children:
|
||||
if child.tag == '':
|
||||
continue
|
||||
match = True
|
||||
if tag and child.tag != tag:
|
||||
match = False
|
||||
if class_ and not child.has_class(class_):
|
||||
match = False
|
||||
if match:
|
||||
yield child
|
||||
yield from child.find_all(tag, class_)
|
||||
|
||||
def find(self, tag=None, class_=None):
|
||||
return next(self.find_all(tag, class_), None)
|
||||
|
||||
def get_text(self):
|
||||
if self.tag == '':
|
||||
return self.text
|
||||
return ''.join(c.get_text() for c in self.children)
|
||||
|
||||
|
||||
class DOMBuilder(HTMLParser):
|
||||
"""Build a minimal DOM tree from HTML."""
|
||||
|
||||
VOID_ELEMENTS = frozenset([
|
||||
'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
|
||||
'link', 'meta', 'param', 'source', 'track', 'wbr',
|
||||
])
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.root = Node('root')
|
||||
self._cur = self.root
|
||||
|
||||
def handle_starttag(self, tag, attrs):
|
||||
node = Node(tag, attrs)
|
||||
node.parent = self._cur
|
||||
self._cur.children.append(node)
|
||||
if tag not in self.VOID_ELEMENTS:
|
||||
self._cur = node
|
||||
|
||||
def handle_endtag(self, tag):
|
||||
# Walk up to find the matching open tag (tolerates misnesting)
|
||||
n = self._cur
|
||||
while n and n.tag != tag and n.parent:
|
||||
n = n.parent
|
||||
if n and n.parent:
|
||||
self._cur = n.parent
|
||||
|
||||
def handle_data(self, data):
|
||||
t = Node()
|
||||
t.text = data
|
||||
t.parent = self._cur
|
||||
self._cur.children.append(t)
|
||||
|
||||
def handle_entityref(self, name):
|
||||
self.handle_data(unescape(f'&{name};'))
|
||||
|
||||
def handle_charref(self, name):
|
||||
self.handle_data(unescape(f'&#{name};'))
|
||||
|
||||
|
||||
def parse_html(path):
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
html = f.read()
|
||||
builder = DOMBuilder()
|
||||
builder.feed(html)
|
||||
return builder.root
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Content extraction
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
SKIP_CLASSES = {
|
||||
'message_controls', 'message_length_controller',
|
||||
'code-buttons-container', 'copy_codeblock', 'code_external_link',
|
||||
'message_edit_notice', 'edit-notifications',
|
||||
}
|
||||
|
||||
def should_skip(node):
|
||||
return bool(SKIP_CLASSES & set(node.cls.split()))
|
||||
|
||||
|
||||
def extract_content(node):
|
||||
"""Recursively convert a message_content node into readable text."""
|
||||
parts = []
|
||||
for child in node.children:
|
||||
# Text node
|
||||
if child.tag == '':
|
||||
parts.append(child.text)
|
||||
continue
|
||||
|
||||
if should_skip(child):
|
||||
continue
|
||||
|
||||
cls_set = set(child.cls.split())
|
||||
|
||||
# Code block wrappers (div.codehilite / div.zulip-code-block)
|
||||
if child.tag == 'div' and ({'codehilite', 'zulip-code-block'} & cls_set):
|
||||
code = child.find('code')
|
||||
lang = child.attrs.get('data-code-language', '')
|
||||
text = code.get_text() if code else child.get_text()
|
||||
parts.append(f'\n```{lang}\n{text}```\n')
|
||||
continue
|
||||
|
||||
# <pre> (bare code blocks without wrapper div)
|
||||
if child.tag == 'pre':
|
||||
code = child.find('code')
|
||||
text = code.get_text() if code else child.get_text()
|
||||
parts.append(f'\n```\n{text}```\n')
|
||||
continue
|
||||
|
||||
# Inline <code>
|
||||
if child.tag == 'code':
|
||||
parts.append(f'`{child.get_text()}`')
|
||||
continue
|
||||
|
||||
# Paragraph
|
||||
if child.tag == 'p':
|
||||
inner = extract_content(child)
|
||||
parts.append(f'\n{inner}\n')
|
||||
continue
|
||||
|
||||
# Line break
|
||||
if child.tag == 'br':
|
||||
parts.append('\n')
|
||||
continue
|
||||
|
||||
# Links
|
||||
if child.tag == 'a':
|
||||
href = child.attrs.get('href', '')
|
||||
text = child.get_text().strip()
|
||||
if href and not href.startswith('#') and text:
|
||||
parts.append(f'[{text}]({href})')
|
||||
else:
|
||||
parts.append(text)
|
||||
continue
|
||||
|
||||
# Block quotes
|
||||
if child.tag == 'blockquote':
|
||||
bq = extract_content(child).strip()
|
||||
parts.append('\n' + '\n'.join(f'> {l}' for l in bq.split('\n')) + '\n')
|
||||
continue
|
||||
|
||||
# Lists
|
||||
if child.tag in ('ul', 'ol'):
|
||||
for i, li in enumerate(c for c in child.children if c.tag == 'li'):
|
||||
pfx = f'{i+1}.' if child.tag == 'ol' else '-'
|
||||
parts.append(f'\n{pfx} {extract_content(li).strip()}')
|
||||
parts.append('\n')
|
||||
continue
|
||||
|
||||
# User mentions
|
||||
if 'user-mention' in cls_set:
|
||||
parts.append(f'@{child.get_text().strip().lstrip("@")}')
|
||||
continue
|
||||
|
||||
# Emoji
|
||||
if 'emoji' in cls_set:
|
||||
alt = child.attrs.get('alt', '') or child.attrs.get('title', '')
|
||||
if alt:
|
||||
parts.append(alt)
|
||||
continue
|
||||
|
||||
# Recurse into everything else
|
||||
parts.append(extract_content(child))
|
||||
|
||||
return ''.join(parts)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Thread extraction
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def extract_thread(html_path, output_path=None):
|
||||
root = parse_html(html_path)
|
||||
|
||||
# Find the message list
|
||||
msg_list = root.find('div', class_='message-list')
|
||||
if not msg_list:
|
||||
print("ERROR: Could not find message list.", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Topic header
|
||||
header = msg_list.find('div', class_='message_header')
|
||||
stream_name = topic_name = date_str = ''
|
||||
if header:
|
||||
el = header.find('span', class_='message-header-stream-name')
|
||||
if el: stream_name = el.get_text().strip()
|
||||
el = header.find('span', class_='stream-topic-inner')
|
||||
if el: topic_name = el.get_text().strip()
|
||||
el = header.find('span', class_='recipient_row_date')
|
||||
if el:
|
||||
tr = el.find('span', class_='timerender-content')
|
||||
if tr:
|
||||
date_str = tr.attrs.get('data-tippy-content', '') or tr.get_text().strip()
|
||||
|
||||
# Messages
|
||||
messages = []
|
||||
for row in msg_list.find_all('div', class_='message_row'):
|
||||
if not row.has_class('messagebox-includes-sender'):
|
||||
continue
|
||||
|
||||
msg = {}
|
||||
|
||||
sn = row.find('span', class_='sender_name_text')
|
||||
if sn:
|
||||
un = sn.find('span', class_='user-name')
|
||||
msg['sender'] = (un or sn).get_text().strip()
|
||||
|
||||
tm = row.find('a', class_='message-time')
|
||||
if tm:
|
||||
msg['time'] = tm.get_text().strip()
|
||||
|
||||
cd = row.find('div', class_='message_content')
|
||||
if cd:
|
||||
text = extract_content(cd)
|
||||
text = re.sub(r'\n{3,}', '\n\n', text).strip()
|
||||
msg['content'] = text
|
||||
|
||||
# Reactions
|
||||
reactions = []
|
||||
for rx in row.find_all('div', class_='message_reaction'):
|
||||
em = rx.find('div', class_='emoji_alt_code')
|
||||
if em:
|
||||
reactions.append(em.get_text().strip())
|
||||
else:
|
||||
img = rx.find(tag='img')
|
||||
if img:
|
||||
reactions.append(img.attrs.get('alt', ''))
|
||||
cnt = rx.find('span', class_='message_reaction_count')
|
||||
if cnt and reactions:
|
||||
c = cnt.get_text().strip()
|
||||
if c and c != '1':
|
||||
reactions[-1] += f' x{c}'
|
||||
if reactions:
|
||||
msg['reactions'] = reactions
|
||||
|
||||
if msg.get('content') or msg.get('sender'):
|
||||
messages.append(msg)
|
||||
|
||||
# Format
|
||||
lines = [
|
||||
'=' * 70,
|
||||
f'# {stream_name} > {topic_name}',
|
||||
]
|
||||
if date_str:
|
||||
lines.append(f'# Started: {date_str}')
|
||||
lines += [f'# Messages: {len(messages)}', '=' * 70, '']
|
||||
|
||||
for msg in messages:
|
||||
lines.append(f'--- {msg.get("sender","?")} [{msg.get("time","")}] ---')
|
||||
lines.append(msg.get('content', ''))
|
||||
if msg.get('reactions'):
|
||||
lines.append(f' Reactions: {", ".join(msg["reactions"])}')
|
||||
lines.append('')
|
||||
|
||||
result = '\n'.join(lines)
|
||||
if output_path:
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write(result)
|
||||
print(f"Written {len(messages)} messages to {output_path}")
|
||||
else:
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 2:
|
||||
print(f"Usage: {sys.argv[0]} input.html [output.txt]")
|
||||
sys.exit(1)
|
||||
extract_thread(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None)
|
||||
|
||||
9
.github/workflows/awaiting-manual.yml
vendored
9
.github/workflows/awaiting-manual.yml
vendored
@@ -2,16 +2,19 @@ name: Check awaiting-manual label
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
check-awaiting-manual:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check awaiting-manual label
|
||||
id: check-awaiting-manual-label
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request_target'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
@@ -28,7 +31,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Wait for manual compatibility
|
||||
if: github.event_name == 'pull_request' && steps.check-awaiting-manual-label.outputs.awaiting == 'true'
|
||||
if: github.event_name == 'pull_request_target' && steps.check-awaiting-manual-label.outputs.awaiting == 'true'
|
||||
run: |
|
||||
echo "::notice title=Awaiting manual::PR is marked 'awaiting-manual' but neither 'breaks-manual' nor 'builds-manual' labels are present."
|
||||
echo "This check will remain in progress until the PR is updated with appropriate manual compatibility labels."
|
||||
|
||||
9
.github/workflows/awaiting-mathlib.yml
vendored
9
.github/workflows/awaiting-mathlib.yml
vendored
@@ -2,16 +2,19 @@ name: Check awaiting-mathlib label
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
check-awaiting-mathlib:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check awaiting-mathlib label
|
||||
id: check-awaiting-mathlib-label
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request_target'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
@@ -28,7 +31,7 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Wait for mathlib compatibility
|
||||
if: github.event_name == 'pull_request' && steps.check-awaiting-mathlib-label.outputs.awaiting == 'true'
|
||||
if: github.event_name == 'pull_request_target' && steps.check-awaiting-mathlib-label.outputs.awaiting == 'true'
|
||||
run: |
|
||||
echo "::notice title=Awaiting mathlib::PR is marked 'awaiting-mathlib' but neither 'breaks-mathlib' nor 'builds-mathlib' labels are present."
|
||||
echo "This check will remain in progress until the PR is updated with appropriate mathlib compatibility labels."
|
||||
|
||||
26
.github/workflows/build-template.yml
vendored
26
.github/workflows/build-template.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
||||
LSAN_OPTIONS: max_leaks=10
|
||||
# somehow MinGW clang64 (or cmake?) defaults to `g++` even though it doesn't exist
|
||||
CXX: c++
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.15
|
||||
MACOSX_DEPLOYMENT_TARGET: 11.0
|
||||
steps:
|
||||
- name: Install Nix
|
||||
uses: DeterminateSystems/nix-installer-action@main
|
||||
@@ -66,16 +66,10 @@ jobs:
|
||||
brew install ccache tree zstd coreutils gmp libuv
|
||||
if: runner.os == 'macOS'
|
||||
- name: Checkout
|
||||
if: (!endsWith(matrix.os, '-with-cache'))
|
||||
uses: actions/checkout@v6
|
||||
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 }}
|
||||
- name: Namespace Checkout
|
||||
if: endsWith(matrix.os, '-with-cache')
|
||||
uses: namespacelabs/nscloud-checkout-action@v8
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Open Nix shell once
|
||||
run: true
|
||||
if: runner.os == 'Linux'
|
||||
@@ -85,7 +79,7 @@ jobs:
|
||||
- name: CI Merge Checkout
|
||||
run: |
|
||||
git fetch --depth=1 origin ${{ github.sha }}
|
||||
git checkout FETCH_HEAD flake.nix flake.lock script/prepare-* tests/lean/run/importStructure.lean
|
||||
git checkout FETCH_HEAD flake.nix flake.lock script/prepare-* tests/elab/importStructure.lean
|
||||
if: github.event_name == 'pull_request'
|
||||
# (needs to be after "Checkout" so files don't get overridden)
|
||||
- name: Setup emsdk
|
||||
@@ -235,25 +229,21 @@ jobs:
|
||||
# prefix `if` above with `always` so it's run even if tests failed
|
||||
if: always() && steps.test.conclusion != 'skipped'
|
||||
- name: Check Test Binary
|
||||
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
|
||||
run: ${{ matrix.binary-check }} tests/compile/534.lean.out
|
||||
if: (!matrix.cross) && steps.test.conclusion != 'skipped'
|
||||
- name: Build Stage 2
|
||||
run: |
|
||||
make -C build -j$NPROC stage2
|
||||
if: matrix.test-speedcenter
|
||||
if: matrix.test-bench
|
||||
- name: Check Stage 3
|
||||
run: |
|
||||
make -C build -j$NPROC check-stage3
|
||||
if: matrix.check-stage3
|
||||
- name: Test Speedcenter Benchmarks
|
||||
- name: Test Benchmarks
|
||||
run: |
|
||||
# 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
|
||||
cd tests/bench
|
||||
nix shell .#temci -c temci exec --config speedcenter.yaml --included_blocks fast --runs 1
|
||||
if: matrix.test-speedcenter
|
||||
cd tests
|
||||
nix develop -c make -C ../build -j$NPROC bench
|
||||
if: matrix.test-bench
|
||||
- name: Check rebootstrap
|
||||
run: |
|
||||
set -e
|
||||
|
||||
5
.github/workflows/check-stdlib-flags.yml
vendored
5
.github/workflows/check-stdlib-flags.yml
vendored
@@ -1,9 +1,12 @@
|
||||
name: Check stdlib_flags.h modifications
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
check-stdlib-flags:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -258,8 +258,8 @@ jobs:
|
||||
"check-rebootstrap": level >= 1,
|
||||
"check-stage3": level >= 2,
|
||||
"test": true,
|
||||
// NOTE: `test-speedcenter` currently seems to be broken on `ubuntu-latest`
|
||||
"test-speedcenter": large && level >= 2,
|
||||
// NOTE: `test-bench` currently seems to be broken on `ubuntu-latest`
|
||||
"test-bench": large && level >= 2,
|
||||
// We are not warning-free yet on all platforms, start here
|
||||
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-Werror",
|
||||
},
|
||||
@@ -269,6 +269,8 @@ jobs:
|
||||
"enabled": level >= 2,
|
||||
"test": true,
|
||||
"CMAKE_PRESET": "reldebug",
|
||||
// * `elab_bench/big_do` crashes with exit code 134
|
||||
"CTEST_OPTIONS": "-E 'elab_bench/big_do'",
|
||||
},
|
||||
{
|
||||
"name": "Linux fsanitize",
|
||||
|
||||
10
.github/workflows/pr-body.yml
vendored
10
.github/workflows/pr-body.yml
vendored
@@ -2,17 +2,23 @@ name: Check PR body for changelog convention
|
||||
|
||||
on:
|
||||
merge_group:
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types: [opened, synchronize, reopened, edited, labeled, converted_to_draft, ready_for_review]
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
check-pr-body:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check PR body
|
||||
if: github.event_name == 'pull_request'
|
||||
if: github.event_name == 'pull_request_target'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
# Safety note: this uses pull_request_target, so the workflow has elevated privileges.
|
||||
# The PR title and body are only used in regex tests (read-only string matching),
|
||||
# never interpolated into shell commands, eval'd, or written to GITHUB_ENV/GITHUB_OUTPUT.
|
||||
script: |
|
||||
const { title, body, labels, draft } = context.payload.pull_request;
|
||||
if (!draft && /^(feat|fix):/.test(title) && !labels.some(label => label.name == "changelog-no")) {
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,7 +1,6 @@
|
||||
*~
|
||||
\#*
|
||||
.#*
|
||||
*.lock
|
||||
.lake
|
||||
lake-manifest.json
|
||||
/build
|
||||
@@ -18,6 +17,7 @@ compile_commands.json
|
||||
*.idea
|
||||
tasks.json
|
||||
settings.json
|
||||
!.claude/settings.json
|
||||
.gdb_history
|
||||
.vscode/*
|
||||
script/__pycache__
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
|
||||
if(NOT CMAKE_GENERATOR MATCHES "Makefiles")
|
||||
message(FATAL_ERROR "Only makefile generators are supported")
|
||||
endif()
|
||||
|
||||
option(USE_MIMALLOC "use mimalloc" ON)
|
||||
|
||||
@@ -70,13 +74,7 @@ if(NOT CMAKE_SYSTEM_NAME MATCHES "Emscripten")
|
||||
BUILD_IN_SOURCE ON
|
||||
INSTALL_COMMAND ""
|
||||
)
|
||||
set(
|
||||
CADICAL
|
||||
${CMAKE_BINARY_DIR}/cadical/cadical${CMAKE_EXECUTABLE_SUFFIX}
|
||||
CACHE FILEPATH
|
||||
"path to cadical binary"
|
||||
FORCE
|
||||
)
|
||||
set(CADICAL ${CMAKE_BINARY_DIR}/cadical/cadical${CMAKE_EXECUTABLE_SUFFIX})
|
||||
list(APPEND EXTRA_DEPENDS cadical)
|
||||
endif()
|
||||
list(APPEND CL_ARGS -DCADICAL=${CADICAL})
|
||||
@@ -153,6 +151,7 @@ ExternalProject_Add(
|
||||
INSTALL_COMMAND ""
|
||||
DEPENDS stage2
|
||||
EXCLUDE_FROM_ALL ON
|
||||
STEP_TARGETS configure
|
||||
)
|
||||
|
||||
# targets forwarded to appropriate stages
|
||||
@@ -163,6 +162,25 @@ add_custom_target(update-stage0-commit COMMAND $(MAKE) -C stage1 update-stage0-c
|
||||
|
||||
add_custom_target(test COMMAND $(MAKE) -C stage1 test DEPENDS stage1)
|
||||
|
||||
add_custom_target(
|
||||
bench
|
||||
COMMAND $(MAKE) -C stage2
|
||||
COMMAND $(MAKE) -C stage2 -j1 bench
|
||||
DEPENDS stage2
|
||||
)
|
||||
add_custom_target(
|
||||
bench-part1
|
||||
COMMAND $(MAKE) -C stage2
|
||||
COMMAND $(MAKE) -C stage2 -j1 bench-part1
|
||||
DEPENDS stage2
|
||||
)
|
||||
add_custom_target(
|
||||
bench-part2
|
||||
COMMAND $(MAKE) -C stage2
|
||||
COMMAND $(MAKE) -C stage2 -j1 bench-part2
|
||||
DEPENDS stage2
|
||||
)
|
||||
|
||||
add_custom_target(clean-stdlib COMMAND $(MAKE) -C stage1 clean-stdlib DEPENDS stage1)
|
||||
|
||||
install(CODE "execute_process(COMMAND make -C stage1 install)")
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
"SMALL_ALLOCATOR": "OFF",
|
||||
"USE_MIMALLOC": "OFF",
|
||||
"BSYMBOLIC": "OFF",
|
||||
"LEAN_TEST_VARS": "MAIN_STACK_SIZE=16000 LSAN_OPTIONS=max_leaks=10"
|
||||
"LEAN_TEST_VARS": "MAIN_STACK_SIZE=16000 TEST_STACK_SIZE=16000 LSAN_OPTIONS=max_leaks=10"
|
||||
},
|
||||
"generator": "Unix Makefiles",
|
||||
"binaryDir": "${sourceDir}/build/sanitize"
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# Test Suite
|
||||
|
||||
**Warning:** This document is partially outdated.
|
||||
It describes the old test suite, which is currently in the process of being replaced.
|
||||
The new test suite's documentation can be found at [`tests/README.md`](../../tests/README.md).
|
||||
|
||||
After [building Lean](../make/index.md) you can run all the tests using
|
||||
```
|
||||
cd build/release
|
||||
|
||||
@@ -1 +1 @@
|
||||
lean4
|
||||
../../../build/release/stage1
|
||||
|
||||
@@ -1 +1 @@
|
||||
lean4
|
||||
build/release/stage1
|
||||
|
||||
@@ -2,21 +2,9 @@
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
},
|
||||
{
|
||||
"path": "src"
|
||||
},
|
||||
{
|
||||
"path": "tests"
|
||||
},
|
||||
{
|
||||
"path": "script"
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
// Open terminal at root, not current workspace folder
|
||||
// (there is not way to directly refer to the root folder included as `.` above)
|
||||
"terminal.integrated.cwd": "${workspaceFolder:src}/..",
|
||||
"files.insertFinalNewline": true,
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"cmake.buildDirectory": "${workspaceFolder}/build/release",
|
||||
|
||||
@@ -83,7 +83,7 @@ def main (args : List String) : IO Unit := do
|
||||
lastRSS? := some rss
|
||||
|
||||
let avgRSSDelta := totalRSSDelta / (n - 2)
|
||||
IO.println s!"avg-reelab-rss-delta: {avgRSSDelta}"
|
||||
IO.println s!"measurement: avg-reelab-rss-delta {avgRSSDelta*1024} b"
|
||||
|
||||
let _ ← Ipc.collectDiagnostics requestNo uri versionNo
|
||||
(← Ipc.stdin).writeLspMessage (Message.notification "exit" none)
|
||||
|
||||
@@ -82,7 +82,7 @@ def main (args : List String) : IO Unit := do
|
||||
lastRSS? := some rss
|
||||
|
||||
let avgRSSDelta := totalRSSDelta / (n - 2)
|
||||
IO.println s!"avg-reelab-rss-delta: {avgRSSDelta}"
|
||||
IO.println s!"measurement: avg-reelab-rss-delta {avgRSSDelta*1024} b"
|
||||
|
||||
let _ ← Ipc.collectDiagnostics requestNo uri versionNo
|
||||
Ipc.shutdown requestNo
|
||||
|
||||
@@ -9,5 +9,5 @@ find -regex '.*/CMakeLists\.txt\(\.in\)?\|.*\.cmake\(\.in\)?' \
|
||||
! -path "./stage0/*" \
|
||||
-exec \
|
||||
uvx gersemi --in-place --line-length 120 --indent 2 \
|
||||
--definitions src/cmake/Modules/ src/CMakeLists.txt \
|
||||
--definitions src/cmake/Modules/ src/CMakeLists.txt tests/CMakeLists.txt \
|
||||
-- {} +
|
||||
|
||||
@@ -1 +1 @@
|
||||
lean4
|
||||
../build/release/stage1
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
# Profile a Lean binary with demangled names.
|
||||
#
|
||||
# Usage:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
rm -r stage0 || true
|
||||
rm -rf stage0 || true
|
||||
# don't copy untracked files
|
||||
# `:!` is git glob flavor for exclude patterns
|
||||
for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
|
||||
|
||||
@@ -924,8 +924,8 @@ def main():
|
||||
|
||||
print(f" ✅ Bump branch {bump_branch} exists")
|
||||
|
||||
# For batteries and mathlib4, update the lean-toolchain to the latest nightly
|
||||
if branch_created and name in ["batteries", "mathlib4"]:
|
||||
# Update the lean-toolchain to the latest nightly for newly created bump branches
|
||||
if branch_created:
|
||||
latest_nightly = get_latest_nightly_tag(github_token)
|
||||
if latest_nightly:
|
||||
nightly_toolchain = f"leanprover/lean4:{latest_nightly}"
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
cmake_policy(SET CMP0054 NEW)
|
||||
cmake_policy(SET CMP0110 NEW)
|
||||
cmake_minimum_required(VERSION 3.21)
|
||||
if(NOT CMAKE_GENERATOR MATCHES "Unix Makefiles")
|
||||
message(FATAL_ERROR "The only supported CMake generator at the moment is 'Unix Makefiles'")
|
||||
endif()
|
||||
|
||||
@@ -142,7 +142,7 @@ is classically true but not constructively. -/
|
||||
|
||||
/-- Transfer decidability of `¬ p` to decidability of `p`. -/
|
||||
-- This can not be an instance as it would be tried everywhere.
|
||||
@[instance_reducible]
|
||||
@[implicit_reducible]
|
||||
def decidable_of_decidable_not (p : Prop) [h : Decidable (¬ p)] : Decidable p :=
|
||||
match h with
|
||||
| isFalse h => isTrue (Classical.not_not.mp h)
|
||||
|
||||
63
src/Init/Control/Do.lean
Normal file
63
src/Init/Control/Do.lean
Normal file
@@ -0,0 +1,63 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Sebastian Graf
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Except
|
||||
public import Init.Control.Option
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
This module provides specialized wrappers around `ExceptT` to support the `do` elaborator.
|
||||
|
||||
Specifically, the types here are used to tunnel early `return`, `break` and `continue` through
|
||||
non-algebraic higher-order effect combinators such as `tryCatch`.
|
||||
-/
|
||||
|
||||
/-- A wrapper around `ExceptT` signifying early return. -/
|
||||
@[expose]
|
||||
abbrev EarlyReturnT (ρ m α) := ExceptT ρ m α
|
||||
|
||||
/-- Exit a computation by returning a value `r : ρ` early. -/
|
||||
@[always_inline, inline, expose]
|
||||
abbrev EarlyReturnT.return {ρ m α} [Monad m] (r : ρ) : EarlyReturnT ρ m α :=
|
||||
throw r
|
||||
|
||||
/-- A specialization of `Except.casesOn`. -/
|
||||
@[always_inline, inline, expose]
|
||||
abbrev EarlyReturn.runK {ρ α : Type u} {β : Type v} (x : Except ρ α) (ret : ρ → β) (pure : α → β) : β :=
|
||||
x.casesOn ret pure
|
||||
|
||||
/-- A wrapper around `OptionT` signifying `break` in a loop. -/
|
||||
@[expose]
|
||||
abbrev BreakT := OptionT
|
||||
|
||||
/-- Exit a loop body via `break`. -/
|
||||
@[always_inline, inline, expose]
|
||||
abbrev BreakT.break {m : Type w → Type x} [Monad m] : BreakT m α := failure
|
||||
|
||||
/-- A specialization of `Option.casesOn`. -/
|
||||
@[always_inline, inline, expose]
|
||||
abbrev Break.runK {α : Type u} {β : Type v} (x : Option α) (breakK : Unit → β) (successK : α → β) : β :=
|
||||
-- Note: The matcher below is used in the elaborator targeting `forIn` loops.
|
||||
-- If you change the order of match arms here, you may need to adjust the elaborator.
|
||||
match x with
|
||||
| some a => successK a
|
||||
| none => breakK ()
|
||||
|
||||
/-- A wrapper around `OptionT` signifying `continue` in a loop. -/
|
||||
@[expose]
|
||||
abbrev ContinueT := OptionT
|
||||
|
||||
/-- Exit a loop body via `continue`. -/
|
||||
@[always_inline, inline, expose]
|
||||
abbrev ContinueT.continue {m : Type w → Type x} [Monad m] : ContinueT m α := failure
|
||||
|
||||
/-- A specialization of `Option.casesOn`. -/
|
||||
@[always_inline, inline, expose]
|
||||
abbrev Continue.runK {α : Type u} {β : Type v} (x : Option α) (continueK : Unit → β) (successK : α → β) : β :=
|
||||
x.casesOn continueK (fun a _ => successK a) ()
|
||||
@@ -79,3 +79,11 @@ instance : LawfulMonadAttach Id where
|
||||
exact x.run.2
|
||||
|
||||
end Id
|
||||
|
||||
/-- Turn a collection with a pure `ForIn` instance into an array. -/
|
||||
def ForIn.toArray {α : Type u} [inst : ForIn Id ρ α] (xs : ρ) : Array α :=
|
||||
ForIn.forIn xs Array.empty (fun a acc => pure (.yield (acc.push a))) |> Id.run
|
||||
|
||||
/-- Turn a collection with a pure `ForIn` instance into a list. -/
|
||||
def ForIn.toList {α : Type u} [ForIn Id ρ α] (xs : ρ) : List α :=
|
||||
ForIn.toArray xs |>.toList
|
||||
|
||||
@@ -258,7 +258,6 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (OptionT m) where
|
||||
rw [← bind_pure_comp]
|
||||
rfl
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp] theorem run_controlAt [Monad m] [LawfulMonad m] (f : ({β : Type u} → OptionT m β → m (stM m (OptionT m) β)) → m (stM m (OptionT m) α)) :
|
||||
OptionT.run (controlAt m f) = f fun x => x.run := by
|
||||
simp [controlAt, Option.elimM, Option.elim]
|
||||
@@ -346,7 +345,6 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (ReaderT ρ m) where
|
||||
ReaderT.run (liftWith f) ctx = (f fun x => x.run ctx) :=
|
||||
rfl
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp] theorem run_controlAt [Monad m] [LawfulMonad m] (f : ({β : Type u} → ReaderT ρ m β → m (stM m (ReaderT ρ m) β)) → m (stM m (ReaderT ρ m) α)) (ctx : ρ) :
|
||||
ReaderT.run (controlAt m f) ctx = f fun x => x.run ctx := by
|
||||
simp [controlAt]
|
||||
@@ -441,13 +439,11 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateT σ m) where
|
||||
@[simp] theorem run_restoreM [Monad m] [LawfulMonad m] (x : stM m (StateT σ m) α) (s : σ) :
|
||||
StateT.run (restoreM x) s = pure x := by
|
||||
simp [restoreM, MonadControl.restoreM]
|
||||
rfl
|
||||
|
||||
@[simp] theorem run_liftWith [Monad m] [LawfulMonad m] (f : ({β : Type u} → StateT σ m β → m (stM m (StateT σ m) β)) → m α) (s : σ) :
|
||||
StateT.run (liftWith f) s = ((·, s) <$> f fun x => x.run s) := by
|
||||
simp [liftWith, MonadControl.liftWith, Function.comp_def]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp] theorem run_controlAt [Monad m] [LawfulMonad m] (f : ({β : Type u} → StateT σ m β → m (stM m (StateT σ m) β)) → m (stM m (StateT σ m) α)) (s : σ) :
|
||||
StateT.run (controlAt m f) s = f fun x => x.run s := by
|
||||
simp [controlAt]
|
||||
|
||||
@@ -70,7 +70,7 @@ information to the return value, except a trivial proof of {name}`True`.
|
||||
This instance is used whenever no more useful {name}`MonadAttach` instance can be implemented.
|
||||
It always has a {name}`WeaklyLawfulMonadAttach`, but usually no {name}`LawfulMonadAttach` instance.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
public protected def MonadAttach.trivial {m : Type u → Type v} [Monad m] : MonadAttach m where
|
||||
CanReturn _ _ := True
|
||||
attach x := (⟨·, .intro⟩) <$> x
|
||||
|
||||
@@ -1339,10 +1339,10 @@ transitive and contains `r`. `TransGen r a z` if and only if there exists a sequ
|
||||
-/
|
||||
inductive Relation.TransGen {α : Sort u} (r : α → α → Prop) : α → α → Prop
|
||||
/-- If `r a b`, then `TransGen r a b`. This is the base case of the transitive closure. -/
|
||||
| single {a b} : r a b → TransGen r a b
|
||||
| single {a b : α} : r a b → TransGen r a b
|
||||
/-- If `TransGen r a b` and `r b c`, then `TransGen r a c`.
|
||||
This is the inductive case of the transitive closure. -/
|
||||
| tail {a b c} : TransGen r a b → r b c → TransGen r a c
|
||||
| tail {a b c : α} : TransGen r a b → r b c → TransGen r a c
|
||||
|
||||
/-- The transitive closure is transitive. -/
|
||||
theorem Relation.TransGen.trans {α : Sort u} {r : α → α → Prop} {a b c} :
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Do
|
||||
public import Init.GetElem
|
||||
public import Init.Data.List.ToArrayImpl
|
||||
import all Init.Data.List.ToArrayImpl
|
||||
@@ -93,7 +94,7 @@ theorem ext' {xs ys : Array α} (h : xs.toList = ys.toList) : xs = ys := by
|
||||
|
||||
@[simp, grind =] theorem getElem?_toList {xs : Array α} {i : Nat} : xs.toList[i]? = xs[i]? := by
|
||||
simp only [getElem?_def, getElem_toList]
|
||||
simp only [Array.size]; rfl
|
||||
simp only [Array.size]
|
||||
|
||||
/-- `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
|
||||
@@ -170,6 +171,15 @@ This avoids overhead due to unboxing a `Nat` used as an index.
|
||||
def uget (xs : @& Array α) (i : USize) (h : i.toNat < xs.size) : α :=
|
||||
xs[i.toNat]
|
||||
|
||||
/--
|
||||
Version of `Array.uget` that does not increment the reference count of its result.
|
||||
|
||||
This is only intended for direct use by the compiler.
|
||||
-/
|
||||
@[extern "lean_array_uget_borrowed"]
|
||||
unsafe opaque ugetBorrowed (xs : @& Array α) (i : USize) (h : i.toNat < xs.size) : α :=
|
||||
xs.uget i h
|
||||
|
||||
/--
|
||||
Low-level modification operator which is as fast as a C array write. The modification is performed
|
||||
in-place when the reference to the array is unique.
|
||||
|
||||
@@ -723,7 +723,6 @@ theorem findFinIdx?_eq_bind_find?_finIdxOf? [BEq α] [LawfulBEq α] {xs : Array
|
||||
xs.findFinIdx? p = (xs.find? p).bind (xs.finIdxOf? ·) := by
|
||||
cases xs
|
||||
simp [List.findFinIdx?_eq_bind_find?_finIdxOf?]
|
||||
rfl
|
||||
|
||||
theorem findIdx_eq_getD_bind_find?_idxOf? [BEq α] [LawfulBEq α] {xs : Array α} {p : α → Bool} :
|
||||
xs.findIdx p = ((xs.find? p).bind (xs.idxOf? ·)).getD xs.size := by
|
||||
|
||||
@@ -72,6 +72,9 @@ theorem toArray_eq : List.toArray as = xs ↔ as = xs.toList := by
|
||||
|
||||
/-! ### size -/
|
||||
|
||||
theorem size_singleton {x : α} : #[x].size = 1 := by
|
||||
simp
|
||||
|
||||
theorem eq_empty_of_size_eq_zero (h : xs.size = 0) : xs = #[] := by
|
||||
cases xs
|
||||
simp_all
|
||||
@@ -896,7 +899,7 @@ theorem all_push {xs : Array α} {a : α} {p : α → Bool} :
|
||||
@[simp] theorem getElem_set_ne {xs : Array α} {i : Nat} (h' : i < xs.size) {v : α} {j : Nat}
|
||||
(pj : j < xs.size) (h : i ≠ j) :
|
||||
(xs.set i v)[j]'(by simp [*]) = xs[j] := by
|
||||
simp only [set, ← getElem_toList, List.getElem_set_ne h]; rfl
|
||||
simp only [set, ← getElem_toList, List.getElem_set_ne h]
|
||||
|
||||
@[simp] theorem getElem?_set_ne {xs : Array α} {i : Nat} (h : i < xs.size) {v : α} {j : Nat}
|
||||
(ne : i ≠ j) : (xs.set i v)[j]? = xs[j]? := by
|
||||
@@ -2855,7 +2858,7 @@ theorem getElem?_extract {xs : Array α} {start stop : Nat} :
|
||||
· simp only [length_toList, size_extract, List.length_take, List.length_drop]
|
||||
omega
|
||||
· intro n h₁ h₂
|
||||
simp; rfl
|
||||
simp
|
||||
|
||||
@[simp] theorem extract_size {xs : Array α} : xs.extract 0 xs.size = xs := by
|
||||
apply ext
|
||||
@@ -3483,6 +3486,21 @@ theorem foldl_eq_foldr_reverse {xs : Array α} {f : β → α → β} {b} :
|
||||
theorem foldr_eq_foldl_reverse {xs : Array α} {f : α → β → β} {b} :
|
||||
xs.foldr f b = xs.reverse.foldl (fun x y => f y x) b := by simp
|
||||
|
||||
theorem foldl_eq_apply_foldr {xs : Array α} {f : α → α → α}
|
||||
[Std.Associative f] [Std.LawfulRightIdentity f init] :
|
||||
xs.foldl f x = f x (xs.foldr f init) := by
|
||||
simp [← foldl_toList, ← foldr_toList, List.foldl_eq_apply_foldr]
|
||||
|
||||
theorem foldr_eq_apply_foldl {xs : Array α} {f : α → α → α}
|
||||
[Std.Associative f] [Std.LawfulLeftIdentity f init] :
|
||||
xs.foldr f x = f (xs.foldl f init) x := by
|
||||
simp [← foldl_toList, ← foldr_toList, List.foldr_eq_apply_foldl]
|
||||
|
||||
theorem foldr_eq_foldl {xs : Array α} {f : α → α → α}
|
||||
[Std.Associative f] [Std.LawfulIdentity f init] :
|
||||
xs.foldr f init = xs.foldl f init := by
|
||||
simp [foldl_eq_apply_foldr, Std.LawfulLeftIdentity.left_id]
|
||||
|
||||
@[simp] theorem foldr_push_eq_append {as : Array α} {bs : Array β} {f : α → β} (w : start = as.size) :
|
||||
as.foldr (fun a xs => Array.push xs (f a)) bs start 0 = bs ++ (as.map f).reverse := by
|
||||
subst w
|
||||
@@ -4335,16 +4353,33 @@ def sum_eq_sum_toList := @sum_toList
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_append [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.LeftIdentity (α := α) (· + ·) 0] [Std.LawfulLeftIdentity (α := α) (· + ·) 0]
|
||||
[Std.LawfulLeftIdentity (α := α) (· + ·) 0]
|
||||
{as₁ as₂ : Array α} : (as₁ ++ as₂).sum = as₁.sum + as₂.sum := by
|
||||
simp [← sum_toList, List.sum_append]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_singleton [Add α] [Zero α] [Std.LawfulRightIdentity (· + ·) (0 : α)] {x : α} :
|
||||
#[x].sum = x := by
|
||||
simp [Array.sum_eq_foldr, Std.LawfulRightIdentity.right_id x]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_push [Add α] [Zero α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.LawfulIdentity (· + ·) (0 : α)] {xs : Array α} {x : α} :
|
||||
(xs.push x).sum = xs.sum + x := by
|
||||
simp [Array.sum_eq_foldr, Std.LawfulRightIdentity.right_id, Std.LawfulLeftIdentity.left_id,
|
||||
← Array.foldr_assoc]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_reverse [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.Commutative (α := α) (· + ·)]
|
||||
[Std.LawfulLeftIdentity (α := α) (· + ·) 0] (xs : Array α) : xs.reverse.sum = xs.sum := by
|
||||
simp [← sum_toList, List.sum_reverse]
|
||||
|
||||
theorem sum_eq_foldl [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.LawfulIdentity (· + ·) (0 : α)] {xs : Array α} :
|
||||
xs.sum = xs.foldl (init := 0) (· + ·) := by
|
||||
simp [← sum_toList, List.sum_eq_foldl]
|
||||
|
||||
theorem foldl_toList_eq_flatMap {l : List α} {acc : Array β}
|
||||
{F : Array β → α → Array β} {G : α → List β}
|
||||
(H : ∀ acc a, (F acc a).toList = acc.toList ++ G a) :
|
||||
|
||||
@@ -72,7 +72,6 @@ theorem mapFinIdx_spec {xs : Array α} {f : (i : Nat) → α → (h : i < xs.siz
|
||||
simp only [getElem?_def, size_mapFinIdx, getElem_mapFinIdx]
|
||||
split <;> simp_all
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp, grind =] theorem toList_mapFinIdx {xs : Array α} {f : (i : Nat) → α → (h : i < xs.size) → β} :
|
||||
(xs.mapFinIdx f).toList = xs.toList.mapFinIdx (fun i a h => f i a (by simpa)) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
@@ -106,7 +105,6 @@ theorem mapIdx_spec {f : Nat → α → β} {xs : Array α}
|
||||
xs[i]?.map (f i) := by
|
||||
simp [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp, grind =] theorem toList_mapIdx {f : Nat → α → β} {xs : Array α} :
|
||||
(xs.mapIdx f).toList = xs.toList.mapIdx (fun i a => f i a) := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
@@ -41,7 +41,6 @@ theorem ofFn_succ {f : Fin (n+1) → α} :
|
||||
intro h₃
|
||||
simp only [show i = n by omega]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
ofFn f = (ofFn (fun i => f (i.castLE (Nat.le_add_right n m)))) ++ (ofFn (fun i => f (i.natAdd n))) := by
|
||||
induction m with
|
||||
@@ -108,7 +107,6 @@ theorem ofFnM_succ {n} [Monad m] [LawfulMonad m] {f : Fin (n + 1) → m α} :
|
||||
pure (as.push a)) := by
|
||||
simp [ofFnM, Fin.foldlM_succ_last]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
ofFnM f = (do
|
||||
let as ← ofFnM fun i : Fin n => f (i.castLE (Nat.le_add_right n k))
|
||||
|
||||
@@ -126,6 +126,14 @@ theorem swap_perm {xs : Array α} {i j : Nat} (h₁ : i < xs.size) (h₂ : j < x
|
||||
simp only [swap, perm_iff_toList_perm, toList_set]
|
||||
apply set_set_perm
|
||||
|
||||
theorem Perm.pairwise_iff {R : α → α → Prop} (S : ∀ {x y}, R x y → R y x) {xs ys : Array α}
|
||||
: ∀ _p : xs.Perm ys, xs.toList.Pairwise R ↔ ys.toList.Pairwise R := by
|
||||
simpa only [perm_iff_toList_perm] using List.Perm.pairwise_iff S
|
||||
|
||||
theorem Perm.pairwise {R : α → α → Prop} {xs ys : Array α} (hp : xs ~ ys)
|
||||
(hR : xs.toList.Pairwise R) (hsymm : ∀ {x y}, R x y → R y x) :
|
||||
ys.toList.Pairwise R := (hp.pairwise_iff hsymm).mp hR
|
||||
|
||||
namespace Perm
|
||||
|
||||
set_option linter.indexVariables false in
|
||||
|
||||
@@ -7,7 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Slice.Basic
|
||||
public import Init.Data.Slice.Operations
|
||||
|
||||
public section
|
||||
|
||||
@@ -76,15 +76,17 @@ def Subarray.stop_le_array_size (xs : Subarray α) : xs.stop ≤ xs.array.size :
|
||||
|
||||
namespace Subarray
|
||||
|
||||
/--
|
||||
Computes the size of the subarray.
|
||||
-/
|
||||
def size (s : Subarray α) : Nat :=
|
||||
s.stop - s.start
|
||||
instance : SliceSize (Internal.SubarrayData α) where
|
||||
size s := s.internalRepresentation.stop - s.internalRepresentation.start
|
||||
|
||||
@[grind =, suggest_for Subarray.size]
|
||||
public theorem size_eq {xs : Subarray α} :
|
||||
xs.size = xs.stop - xs.start := by
|
||||
simp [Std.Slice.size, SliceSize.size, start, stop]
|
||||
|
||||
theorem size_le_array_size {s : Subarray α} : s.size ≤ s.array.size := by
|
||||
let ⟨{array, start, stop, start_le_stop, stop_le_array_size}⟩ := s
|
||||
simp only [size, ge_iff_le]
|
||||
simp only [ge_iff_le, size_eq]
|
||||
apply Nat.le_trans (Nat.sub_le stop start)
|
||||
assumption
|
||||
|
||||
|
||||
@@ -2393,4 +2393,412 @@ theorem fastUmulOverflow (x y : BitVec w) :
|
||||
simp [← Nat.pow_add, show w + 1 - (k - 1) + k = w + 1 + 1 by omega] at this
|
||||
omega
|
||||
|
||||
/-! ### Population Count -/
|
||||
|
||||
/-- Extract the `k`-th bit from `x` and extend it to have length `len`. -/
|
||||
def extractAndExtendBit (idx len : Nat) (x : BitVec w) : BitVec len :=
|
||||
BitVec.zeroExtend len (BitVec.extractLsb' idx 1 x)
|
||||
|
||||
|
||||
/-- Recursively extract one bit at a time and extend it to width `w` -/
|
||||
def extractAndExtendAux (k len : Nat) (x : BitVec w) (acc : BitVec (k * len)) (hle : k ≤ w) :
|
||||
BitVec (w * len) :=
|
||||
match hwi : w - k with
|
||||
| 0 => acc.cast (by simp [show w = k by omega])
|
||||
| n' + 1 =>
|
||||
let acc' := extractAndExtendBit k len x ++ acc
|
||||
extractAndExtendAux (k + 1) len x (acc'.cast (by simp [Nat.add_mul]; omega)) (by omega)
|
||||
termination_by w - k
|
||||
|
||||
/-- We instantiate `extractAndExtendAux` to extend each bit to `len`, extending
|
||||
each bit in `x` to have width `w` and returning a `BitVec (w * w)`. -/
|
||||
def extractAndExtend (len : Nat) (x : BitVec w) : BitVec (w * len) :=
|
||||
extractAndExtendAux 0 len x ((0#0).cast (by simp)) (by omega)
|
||||
|
||||
/--
|
||||
Construct a layer of the parallel-prefix-sum tree by summing two-by-two all the
|
||||
`w`-long words in `oldLayer`, returning a bitvector containing `(oldLen + 1) / 2`
|
||||
flattened `w`-long words, each resulting from an addition.
|
||||
-/
|
||||
def cpopLayer (oldLayer : BitVec (len * w)) (newLayer : BitVec (iterNum * w))
|
||||
(hold : 2 * (iterNum - 1) < len) : BitVec (((len + 1)/2) * w) :=
|
||||
if hlen : len - (iterNum * 2) = 0 then
|
||||
have : ((len + 1)/2) = iterNum := by omega
|
||||
newLayer.cast (by simp [this])
|
||||
else
|
||||
let op1 := oldLayer.extractLsb' ((2 * iterNum) * w) w
|
||||
let op2 := oldLayer.extractLsb' ((2 * iterNum + 1) * w) w
|
||||
let newLayer' := (op1 + op2) ++ newLayer
|
||||
have hcast : w + iterNum * w = (iterNum + 1) * w := by simp [Nat.add_mul]; omega
|
||||
cpopLayer oldLayer (newLayer'.cast hcast) (by omega)
|
||||
termination_by len - (iterNum * 2)
|
||||
|
||||
/--
|
||||
Given a `BitVec (len * w)` of `len` flattened `w`-long words,
|
||||
construct a binary tree that sums two-by-two the `w`-long words in the previous layer,
|
||||
ultimately returning a single `w`-long words corresponding to the whole addition.
|
||||
-/
|
||||
def cpopTree (l : BitVec (len * w)) : BitVec w :=
|
||||
if h : len = 0 then 0#w
|
||||
else if h : len = 1 then
|
||||
l.cast (by simp [h])
|
||||
else
|
||||
cpopTree (cpopLayer l 0#(0 * w) (by omega))
|
||||
termination_by len
|
||||
|
||||
/--
|
||||
Given flattened bitvector `x : BitVec w` and a length `l : Nat`,
|
||||
construct a parallel prefix sum circuit adding each available `l`-long word in `x`.
|
||||
-/
|
||||
def cpopRec (x : BitVec w) : BitVec w :=
|
||||
if hw : 1 < w then
|
||||
let extendedBits := x.extractAndExtend w
|
||||
(cpopTree extendedBits).cast (by simp)
|
||||
else if hw' : 0 < w then
|
||||
x
|
||||
else
|
||||
0#w
|
||||
|
||||
/-- Recursive addition of the elements in a flattened bitvec, starting from the `rem`-th element. -/
|
||||
private def addRecAux (x : BitVec (l * w)) (rem : Nat) (acc : BitVec w) : BitVec w :=
|
||||
match rem with
|
||||
| 0 => acc
|
||||
| n + 1 => x.addRecAux n (acc + x.extractLsb' (n * w) w)
|
||||
|
||||
/-- Recursive addition of the elements in a flattened bitvec. -/
|
||||
private def addRec (x : BitVec (l * w)) : BitVec w := addRecAux x l 0#w
|
||||
|
||||
theorem getLsbD_extractAndExtendBit {x : BitVec w} :
|
||||
(extractAndExtendBit k len x).getLsbD i =
|
||||
(decide (i = 0) && decide (0 < len) && x.getLsbD k) := by
|
||||
simp only [extractAndExtendBit, truncate_eq_setWidth, getLsbD_setWidth, getLsbD_extractLsb',
|
||||
Nat.lt_one_iff]
|
||||
by_cases hi : i = 0
|
||||
<;> simp [hi]
|
||||
|
||||
@[simp]
|
||||
private theorem extractAndExtendAux_zero {k len : Nat} {x : BitVec w}
|
||||
{acc : BitVec (k * len)} (heq : w = k) :
|
||||
extractAndExtendAux k len x acc (by omega) = acc.cast (by simp [heq]) := by
|
||||
unfold extractAndExtendAux
|
||||
split
|
||||
· simp
|
||||
· omega
|
||||
|
||||
private theorem extractLsb'_extractAndExtendAux {k len : Nat} {x : BitVec w}
|
||||
(acc : BitVec (k * len)) (hle : k ≤ w) :
|
||||
(∀ i (_ : i < k), acc.extractLsb' (i * len) len = (x.extractLsb' i 1).setWidth len) →
|
||||
(extractAndExtendAux k len x acc (by omega)).extractLsb' (i * len) len =
|
||||
(x.extractLsb' i 1).setWidth len := by
|
||||
intros hacc
|
||||
induction hwi : w - k generalizing acc k
|
||||
· case zero =>
|
||||
rw [extractAndExtendAux_zero (by omega)]
|
||||
by_cases hj : i < k
|
||||
· apply hacc
|
||||
exact hj
|
||||
· ext l hl
|
||||
have := mul_le_mul_right (n := k) (m := i) len (by omega)
|
||||
simp [← getLsbD_eq_getElem, getLsbD_extractLsb', hl, getLsbD_setWidth,
|
||||
show w ≤ i + l by omega, getLsbD_of_ge acc (i * len + l) (by omega)]
|
||||
· case succ n' ihn' =>
|
||||
rw [extractAndExtendAux]
|
||||
split
|
||||
· omega
|
||||
· apply ihn'
|
||||
· intros i hi
|
||||
have hcast : len + k * len = (k + 1) * len := by
|
||||
simp [Nat.mul_comm, Nat.mul_add, Nat.add_comm]
|
||||
|
||||
by_cases hi' : i < k
|
||||
· have heq : extractLsb' (i * len) len (BitVec.cast hcast (extractAndExtendBit k len x ++ acc)) =
|
||||
extractLsb' (i * len) len ((extractAndExtendBit k len x ++ acc)) := by
|
||||
ext; simp
|
||||
rw [heq, extractLsb'_append_of_lt hi']
|
||||
apply hacc
|
||||
exact hi'
|
||||
· have heq : extractLsb' (i * len) len (BitVec.cast hcast (extractAndExtendBit k len x ++ acc)) =
|
||||
extractLsb' (i * len) len ((extractAndExtendBit k len x ++ acc)) := by
|
||||
ext; simp
|
||||
rw [heq, extractLsb'_append_of_eq (by omega)]
|
||||
simp [show i = k by omega, extractAndExtendBit]
|
||||
· omega
|
||||
|
||||
theorem extractLsb'_cpopLayer {w iterNum i oldLen : Nat} {oldLayer : BitVec (oldLen * w)}
|
||||
{newLayer : BitVec (iterNum * w)} (hold : 2 * (iterNum - 1) < oldLen) :
|
||||
(∀ i (_hi: i < iterNum),
|
||||
newLayer.extractLsb' (i * w) w =
|
||||
oldLayer.extractLsb' ((2 * i) * w) w + (oldLayer.extractLsb' ((2 * i + 1) * w) w)) →
|
||||
extractLsb' (i * w) w (oldLayer.cpopLayer newLayer hold) =
|
||||
extractLsb' (2 * i * w) w oldLayer + extractLsb' ((2 * i + 1) * w) w oldLayer := by
|
||||
intro proof_addition
|
||||
rw [cpopLayer]
|
||||
split
|
||||
· by_cases hi : i < iterNum
|
||||
· simp only [extractLsb'_cast]
|
||||
apply proof_addition
|
||||
exact hi
|
||||
· ext j hj
|
||||
have : iterNum * w ≤ i * w := by refine mul_le_mul_right w (by omega)
|
||||
have : oldLen * w ≤ (2 * i) * w := by refine mul_le_mul_right w (by omega)
|
||||
have : oldLen * w ≤ (2 * i + 1) * w := by refine mul_le_mul_right w (by omega)
|
||||
have hz : extractLsb' (2 * i * w) w oldLayer = 0#w := by
|
||||
ext j hj
|
||||
simp [show oldLen * w ≤ 2 * i * w + j by omega]
|
||||
have hz' : extractLsb' ((2 * i + 1) * w) w oldLayer = 0#w := by
|
||||
ext j hj
|
||||
simp [show oldLen * w ≤ (2 * i + 1) * w + j by omega]
|
||||
simp [show iterNum * w ≤ i * w + j by omega, hz, hz']
|
||||
· generalize hop1 : oldLayer.extractLsb' ((2 * iterNum) * w) w = op1
|
||||
generalize hop2 : oldLayer.extractLsb' ((2 * iterNum + 1) * w) w = op2
|
||||
have hcast : w + iterNum * w = (iterNum + 1) * w := by simp [Nat.add_mul]; omega
|
||||
apply extractLsb'_cpopLayer
|
||||
intros i hi
|
||||
by_cases hlt : i < iterNum
|
||||
· rw [extractLsb'_cast, extractLsb'_append_eq_of_add_le]
|
||||
· apply proof_addition
|
||||
exact hlt
|
||||
· rw [show i * w + w = i * w + 1 * w by omega, ← Nat.add_mul]
|
||||
exact mul_le_mul_right w hlt
|
||||
· rw [extractLsb'_cast, show i = iterNum by omega, extractLsb'_append_eq_left, hop1, hop2]
|
||||
termination_by oldLen - 2 * (iterNum + 1 - 1)
|
||||
|
||||
theorem getLsbD_cpopLayer {w iterNum: Nat} {oldLayer : BitVec (oldLen * w)}
|
||||
{newLayer : BitVec (iterNum * w)} (hold : 2 * (iterNum - 1) < oldLen) :
|
||||
(∀ i (_hi: i < iterNum),
|
||||
newLayer.extractLsb' (i * w) w =
|
||||
oldLayer.extractLsb' ((2 * i) * w) w + (oldLayer.extractLsb' ((2 * i + 1) * w) w)) →
|
||||
(oldLayer.cpopLayer newLayer hold).getLsbD k =
|
||||
(extractLsb' (2 * ((k - k % w) / w) * w) w oldLayer +
|
||||
extractLsb' ((2 * ((k - k % w) / w) + 1) * w) w oldLayer).getLsbD (k % w) := by
|
||||
intro proof_addition
|
||||
by_cases hw0 : w = 0
|
||||
· subst hw0
|
||||
simp
|
||||
· simp only [← extractLsb'_cpopLayer (hold := by omega) proof_addition,
|
||||
Nat.mod_lt (x := k) (y := w) (by omega), getLsbD_eq_getElem, getElem_extractLsb']
|
||||
congr
|
||||
by_cases hmod : k % w = 0
|
||||
· rw [hmod, Nat.sub_zero, Nat.add_zero, Nat.div_mul_cancel (by omega)]
|
||||
· rw [Nat.div_mul_cancel (by exact dvd_sub_mod k), Nat.sub_add_cancel (by exact mod_le k w)]
|
||||
|
||||
@[simp]
|
||||
private theorem addRecAux_zero {x : BitVec (l * w)} {acc : BitVec w} :
|
||||
x.addRecAux 0 acc = acc := rfl
|
||||
|
||||
@[simp]
|
||||
private theorem addRecAux_succ {x : BitVec (l * w)} {n : Nat} {acc : BitVec w} :
|
||||
x.addRecAux (n + 1) acc = x.addRecAux n (acc + extractLsb' (n * w) w x) := rfl
|
||||
|
||||
private theorem addRecAux_eq {x : BitVec (l * w)} {n : Nat} {acc : BitVec w} :
|
||||
x.addRecAux n acc = x.addRecAux n 0#w + acc := by
|
||||
induction n generalizing acc
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n ihn =>
|
||||
simp only [addRecAux_succ, BitVec.zero_add, ihn (acc := extractLsb' (n * w) w x),
|
||||
BitVec.add_assoc, ihn (acc := acc + extractLsb' (n * w) w x), BitVec.add_right_inj]
|
||||
rw [BitVec.add_comm (x := acc)]
|
||||
|
||||
private theorem extractLsb'_addRecAux_of_le {x : BitVec (len * w)} (h : r ≤ k):
|
||||
(extractLsb' 0 (k * w) x).addRecAux r 0#w = x.addRecAux r 0#w := by
|
||||
induction r generalizing x len k
|
||||
· case zero =>
|
||||
simp [addRecAux]
|
||||
· case succ diff ihdiff =>
|
||||
simp only [addRecAux_succ, BitVec.zero_add]
|
||||
have hext : diff * w + w ≤ k * w := by
|
||||
simp only [show diff * w + w = (diff + 1) * w by simp [Nat.add_mul]]
|
||||
exact Nat.mul_le_mul_right w h
|
||||
rw [extractLsb'_extractLsb'_of_le hext, addRecAux_eq (x := x),
|
||||
addRecAux_eq (x := extractLsb' 0 (k * w) x), ihdiff (x := x) (by omega) (k := k)]
|
||||
|
||||
private theorem extractLsb'_extractAndExtend_eq {i len : Nat} {x : BitVec w} :
|
||||
(extractAndExtend len x).extractLsb' (i * len) len = extractAndExtendBit i len x := by
|
||||
unfold extractAndExtend
|
||||
by_cases hilt : i < w
|
||||
· ext j hj
|
||||
simp [extractLsb'_extractAndExtendAux, extractAndExtendBit]
|
||||
· ext k hk
|
||||
have := Nat.mul_le_mul_right (n := w) (k := len) (m := i) (by omega)
|
||||
simp only [extractAndExtendBit, cast_ofNat, getElem_extractLsb', truncate_eq_setWidth,
|
||||
getElem_setWidth, getLsbD_extractLsb', Nat.lt_one_iff]
|
||||
rw [getLsbD_of_ge, getLsbD_of_ge]
|
||||
· simp
|
||||
· omega
|
||||
· omega
|
||||
|
||||
private theorem addRecAux_append_extractLsb' {x : BitVec (len * w)} (ha : 0 < len) :
|
||||
((x.extractLsb' ((len - 1) * w) w ++
|
||||
x.extractLsb' 0 ((len - 1) * w)).cast (m := len * w) hcast).addRecAux len 0#w =
|
||||
x.extractLsb' ((len - 1) * w) w +
|
||||
(x.extractLsb' 0 ((len - 1) * w)).addRecAux (len - 1) 0#w := by
|
||||
simp only [extractLsb'_addRecAux_of_le (k := len - 1) (r := len - 1) (by omega),
|
||||
BitVec.append_extractLsb'_of_lt (hcast := hcast)]
|
||||
have hsucc := addRecAux_succ (x := x) (acc := 0#w) (n := len - 1)
|
||||
rw [BitVec.zero_add, Nat.sub_one_add_one (by omega)] at hsucc
|
||||
rw [hsucc, addRecAux_eq, BitVec.add_comm]
|
||||
|
||||
private theorem Nat.mul_add_le_mul_of_succ_le {a b c : Nat} (h : a + 1 ≤ c) :
|
||||
a * b + b ≤ c * b := by
|
||||
rw [← Nat.succ_mul]
|
||||
exact mul_le_mul_right b h
|
||||
|
||||
/--
|
||||
The recursive addition of `w`-long words on two flattened bitvectors `x` and `y` (with different
|
||||
number of words `len` and `len'`, respectively) returns the same value, if we can prove
|
||||
that each `w`-long word in `x` results from the addition of two `w`-long words in `y`,
|
||||
using exactly all `w`-long words in `y`.
|
||||
-/
|
||||
private theorem addRecAux_eq_of {x : BitVec (len * w)} {y : BitVec (len' * w)}
|
||||
(hlen : len = (len' + 1) / 2) :
|
||||
(∀ (i : Nat) (_h : i < (len' + 1) / 2),
|
||||
extractLsb' (i * w) w x = extractLsb' (2 * i * w) w y + extractLsb' ((2 * i + 1) * w) w y) →
|
||||
x.addRecAux len 0#w = y.addRecAux len' 0#w := by
|
||||
intro hadd
|
||||
induction len generalizing len' y
|
||||
· case zero =>
|
||||
simp [show len' = 0 by omega]
|
||||
· case succ len ih =>
|
||||
have hcast : w + (len + 1 - 1) * w = (len + 1) * w := by
|
||||
simp [Nat.add_mul, Nat.add_comm]
|
||||
have hcast' : w + (len' - 1) * w = len' * w := by
|
||||
rw [Nat.sub_mul, Nat.one_mul,
|
||||
← Nat.add_sub_assoc (by refine Nat.le_mul_of_pos_left w (by omega)), Nat.add_comm]
|
||||
simp
|
||||
rw [addRecAux_succ, ← BitVec.append_extractLsb'_of_lt (x := x) (hcast := hcast)]
|
||||
have happ := addRecAux_append_extractLsb' (len := len + 1) (x := x) (hcast := hcast) (by omega)
|
||||
simp only [Nat.add_one_sub_one, addRecAux_succ, BitVec.zero_add] at happ
|
||||
simp only [Nat.add_one_sub_one, BitVec.zero_add, happ]
|
||||
have := Nat.succ_mul (n := len' - 1) (m := w)
|
||||
rw [succ_eq_add_one, Nat.sub_one_add_one (by omega)] at this
|
||||
by_cases hmod : len' % 2 = 0
|
||||
· /- `sum` results from the addition of the two last elements in `y`, `sum = op1 + op2` -/
|
||||
have := Nat.mul_le_mul_right (n := len' - 1 - 1) (m := len' - 1) (k := w) (by omega)
|
||||
have := Nat.succ_mul (n := len' - 1 - 1) (m := w)
|
||||
have hcast'' : w + (len' - 1 - 1) * w = (len' - 1) * w := by
|
||||
rw [Nat.sub_mul, Nat.one_mul,
|
||||
← Nat.add_sub_assoc (k := w) (by refine Nat.le_mul_of_pos_left w (by omega))]
|
||||
simp
|
||||
rw [succ_eq_add_one, Nat.sub_one_add_one (by omega)] at this
|
||||
rw [← BitVec.append_extractLsb'_of_lt (x := y) (hcast := hcast'),
|
||||
addRecAux_append_extractLsb' (by omega),
|
||||
← BitVec.append_extractLsb'_of_lt (x := extractLsb' 0 ((len' - 1) * w) y) (hcast := hcast''),
|
||||
addRecAux_append_extractLsb' (by omega),
|
||||
extractLsb'_extractLsb'_of_le (by exact Nat.mul_add_le_mul_of_succ_le (by omega)),
|
||||
extractLsb'_extractLsb'_of_le (by omega), ← BitVec.add_assoc, hadd (_h := by omega)]
|
||||
congr 1
|
||||
· rw [show len = (len' + 1) / 2 - 1 by omega, BitVec.add_comm]
|
||||
congr <;> omega
|
||||
· apply ih
|
||||
· omega
|
||||
· intros
|
||||
rw [extractLsb'_extractLsb'_of_le (by exact Nat.mul_add_le_mul_of_succ_le (by omega)),
|
||||
extractLsb'_extractLsb'_of_le (by exact Nat.mul_add_le_mul_of_succ_le (by omega)),
|
||||
extractLsb'_extractLsb'_of_le (by exact Nat.mul_add_le_mul_of_succ_le (by omega)),
|
||||
hadd (_h := by omega)]
|
||||
· /- `sum` results from the addition of the last elements in `y` with `0#w` -/
|
||||
have : len' * w ≤ (len' - 1 + 1) * w := by exact mul_le_mul_right w (by omega)
|
||||
rw [← BitVec.append_extractLsb'_of_lt (x := y) (hcast := hcast'),
|
||||
addRecAux_append_extractLsb' (by omega), hadd (_h := by omega),
|
||||
show 2 * len = len' - 1 by omega]
|
||||
congr 1
|
||||
· rw [BitVec.add_right_eq_self]
|
||||
ext k hk
|
||||
simp only [getElem_extractLsb', getElem_zero]
|
||||
apply getLsbD_of_ge y ((len' - 1 + 1) * w + k) (by omega)
|
||||
· apply ih
|
||||
· omega
|
||||
· intros
|
||||
rw [extractLsb'_extractLsb'_of_le (by exact Nat.mul_add_le_mul_of_succ_le (by omega)),
|
||||
extractLsb'_extractLsb'_of_le (by exact Nat.mul_add_le_mul_of_succ_le (by omega)),
|
||||
extractLsb'_extractLsb'_of_le (by exact Nat.mul_add_le_mul_of_succ_le (by omega)),
|
||||
hadd (_h := by omega)]
|
||||
|
||||
private theorem getLsbD_extractAndExtend_of_lt {x : BitVec w} (hk : k < v) :
|
||||
(x.extractAndExtend v).getLsbD (pos * v + k) = (extractAndExtendBit pos v x).getLsbD k := by
|
||||
simp [← extractLsb'_extractAndExtend_eq (w := w) (len := v) (i := pos) (x := x)]
|
||||
omega
|
||||
|
||||
/--
|
||||
Extracting a bit from a `BitVec.extractAndExtend` is the same as extracting a bit
|
||||
from a zero-extended bit at a certain position in the original bitvector.
|
||||
-/
|
||||
theorem getLsbD_extractAndExtend {x : BitVec w} (hv : 0 < v) :
|
||||
(BitVec.extractAndExtend v x).getLsbD k =
|
||||
(BitVec.extractAndExtendBit ((k - (k % v)) / v) v x).getLsbD (k % v):= by
|
||||
rw [← getLsbD_extractAndExtend_of_lt (by exact mod_lt k hv)]
|
||||
congr
|
||||
by_cases hmod : k % v = 0
|
||||
· simp only [hmod, Nat.sub_zero, Nat.add_zero]
|
||||
rw [Nat.div_mul_cancel (by omega)]
|
||||
· rw [← Nat.div_eq_sub_mod_div]
|
||||
exact Eq.symm (div_add_mod' k v)
|
||||
|
||||
private theorem addRecAux_extractAndExtend_eq_cpopNatRec {x : BitVec w} :
|
||||
(extractAndExtend w x).addRecAux n 0#w = x.cpopNatRec n 0 := by
|
||||
induction n
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n' ihn' =>
|
||||
rw [cpopNatRec_succ, Nat.zero_add, natCast_eq_ofNat, addRecAux_succ, BitVec.zero_add,
|
||||
addRecAux_eq, cpopNatRec_eq, ihn', ofNat_add, natCast_eq_ofNat, BitVec.add_right_inj,
|
||||
extractLsb'_extractAndExtend_eq]
|
||||
ext k hk
|
||||
simp only [extractAndExtendBit, ← getLsbD_eq_getElem, getLsbD_ofNat, hk, decide_true,
|
||||
Bool.true_and, truncate_eq_setWidth, getLsbD_setWidth, getLsbD_extractLsb', Nat.lt_one_iff]
|
||||
by_cases hk0 : k = 0
|
||||
· simp only [hk0, testBit_zero, decide_true, Nat.add_zero, Bool.true_and]
|
||||
cases x.getLsbD n' <;> simp
|
||||
· simp only [show ¬k = 0 by omega, decide_false, Bool.false_and]
|
||||
symm
|
||||
apply testBit_lt_two_pow ?_
|
||||
have : (x.getLsbD n').toNat ≤ 1 := by
|
||||
cases x.getLsbD n' <;> simp
|
||||
have : 1 < 2 ^ k := by exact Nat.one_lt_two_pow hk0
|
||||
omega
|
||||
|
||||
private theorem addRecAux_extractAndExtend_eq_cpop {x : BitVec w} :
|
||||
(extractAndExtend w x).addRecAux w 0#w = x.cpop := by
|
||||
simp only [cpop]
|
||||
apply addRecAux_extractAndExtend_eq_cpopNatRec
|
||||
|
||||
private theorem addRecAux_cpopTree {x : BitVec (len * w)} :
|
||||
addRecAux ((cpopTree x).cast (m := 1 * w) (by simp)) 1 0#w = addRecAux x len 0#w := by
|
||||
unfold cpopTree
|
||||
split
|
||||
· case _ h =>
|
||||
subst h
|
||||
simp [addRecAux]
|
||||
· case _ h =>
|
||||
split
|
||||
· case _ h' =>
|
||||
simp only [addRecAux_succ, Nat.zero_mul, BitVec.zero_add, addRecAux_zero, h']
|
||||
ext; simp
|
||||
· rw [addRecAux_cpopTree]
|
||||
apply BitVec.addRecAux_eq_of (x := cpopLayer x 0#(0 * w) (by omega)) (y := x)
|
||||
· rfl
|
||||
· intros j hj
|
||||
simp [extractLsb'_cpopLayer]
|
||||
termination_by len
|
||||
|
||||
private theorem addRecAux_eq_cpopTree {x : BitVec (len * w)} :
|
||||
x.addRecAux len 0#w = (x.cpopTree).cast (by simp) := by
|
||||
rw [← addRecAux_cpopTree, addRecAux_succ, Nat.zero_mul, BitVec.zero_add, addRecAux_zero]
|
||||
ext k hk
|
||||
simp [← getLsbD_eq_getElem, hk]
|
||||
|
||||
theorem cpop_eq_cpopRec {x : BitVec w} :
|
||||
BitVec.cpop x = BitVec.cpopRec x := by
|
||||
unfold BitVec.cpopRec
|
||||
split
|
||||
· simp [← addRecAux_extractAndExtend_eq_cpop, addRecAux_eq_cpopTree (x := extractAndExtend w x)]
|
||||
· split
|
||||
· ext k hk
|
||||
cases hx : x.getLsbD 0
|
||||
<;> simp [hx, cpop, ← getLsbD_eq_getElem, show k = 0 by omega, show w = 1 by omega]
|
||||
· have hw : w = 0 := by omega
|
||||
subst hw
|
||||
simp [of_length_zero]
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -1198,7 +1198,7 @@ let x' = x.extractLsb' 7 5 = _ _ 9 8 7
|
||||
(decide (0 < len) &&
|
||||
(decide (start + len ≤ w) &&
|
||||
x.getMsbD (w - (start + len)))) := by
|
||||
simp [BitVec.msb, getMsbD_extractLsb']; rfl
|
||||
simp [BitVec.msb, getMsbD_extractLsb']
|
||||
|
||||
@[simp, grind =] theorem getElem_extract {hi lo : Nat} {x : BitVec n} {i : Nat} (h : i < hi - lo + 1) :
|
||||
(extractLsb hi lo x)[i] = getLsbD x (lo+i) := by
|
||||
@@ -1234,7 +1234,7 @@ let x' = x.extractLsb' 7 5 = _ _ 9 8 7
|
||||
|
||||
@[simp, grind =] theorem msb_extractLsb {hi lo : Nat} {x : BitVec w} :
|
||||
(extractLsb hi lo x).msb = (decide (max hi lo < w) && x.getMsbD (w - 1 - max hi lo)) := by
|
||||
simp [BitVec.msb]; rfl
|
||||
simp [BitVec.msb]
|
||||
|
||||
theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h : len > 0) :
|
||||
x.extractLsb' start len = (x.extractLsb (len - 1 + start) start).cast (by omega) := by
|
||||
@@ -2784,7 +2784,14 @@ theorem msb_append {x : BitVec w} {y : BitVec v} :
|
||||
@[simp] theorem append_zero_width (x : BitVec w) (y : BitVec 0) : x ++ y = x := by
|
||||
ext i ih
|
||||
rw [getElem_append] -- Why does this not work with `simp [getElem_append]`?
|
||||
simp; rfl
|
||||
simp
|
||||
|
||||
theorem append_of_zero_width (x : BitVec w) (y : BitVec v) (h : w = 0) :
|
||||
(x ++ y) = y.cast (by simp [h]) := by
|
||||
ext i ih
|
||||
subst h
|
||||
simp [← getLsbD_eq_getElem, getLsbD_append]
|
||||
omega
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[grind =]
|
||||
@@ -3013,6 +3020,34 @@ theorem extractLsb'_append_extractLsb'_eq_extractLsb' {x : BitVec w} (h : start
|
||||
congr 1
|
||||
omega
|
||||
|
||||
theorem append_extractLsb'_of_lt {x : BitVec (x_len * w)} :
|
||||
(x.extractLsb' ((x_len - 1) * w) w ++ x.extractLsb' 0 ((x_len - 1) * w)).cast hcast = x := by
|
||||
ext i hi
|
||||
simp only [getElem_cast, getElem_append, getElem_extractLsb', Nat.zero_add, dite_eq_ite]
|
||||
rw [← getLsbD_eq_getElem, ite_eq_left_iff, Nat.not_lt]
|
||||
intros
|
||||
simp only [show (x_len - 1) * w + (i - (x_len - 1) * w) = i by omega]
|
||||
|
||||
|
||||
theorem extractLsb'_append_of_lt {x : BitVec (k * w)} {y : BitVec w} (hlt : i < k) :
|
||||
extractLsb' (i * w) w (y ++ x) = extractLsb' (i * w) w x := by
|
||||
ext j hj
|
||||
simp only [← getLsbD_eq_getElem, getLsbD_extractLsb', hj, decide_true, getLsbD_append,
|
||||
Bool.true_and, ite_eq_left_iff, Nat.not_lt]
|
||||
intros h
|
||||
by_cases hw0 : w = 0
|
||||
· subst hw0
|
||||
simp
|
||||
· have : i * w ≤ (k - 1) * w := Nat.mul_le_mul_right w (by omega)
|
||||
have h' : i * w + j < (k - 1 + 1) * w := by simp [Nat.add_mul]; omega
|
||||
rw [Nat.sub_one_add_one (by omega)] at h'
|
||||
omega
|
||||
|
||||
theorem extractLsb'_append_of_eq {x : BitVec (k * w)} {y : BitVec w} (heq : i = k) :
|
||||
extractLsb' (i * w) w (y ++ x) = y := by
|
||||
ext j hj
|
||||
simp [← getLsbD_eq_getElem, getLsbD_append, hj, heq]
|
||||
|
||||
/-- Combine adjacent `~~~ (extractLsb _)'` operations into a single `~~~ (extractLsb _)'`. -/
|
||||
theorem not_extractLsb'_append_not_extractLsb'_eq_not_extractLsb' {x : BitVec w} (h : start₂ = start₁ + len₁) :
|
||||
(~~~ (x.extractLsb' start₂ len₂) ++ ~~~ (x.extractLsb' start₁ len₁)) =
|
||||
@@ -5292,7 +5327,6 @@ theorem and_one_eq_setWidth_ofBool_getLsbD {x : BitVec w} :
|
||||
theorem replicate_zero {x : BitVec w} : x.replicate 0 = 0#0 := by
|
||||
simp [replicate]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp, grind =]
|
||||
theorem replicate_one {w : Nat} {x : BitVec w} :
|
||||
(x.replicate 1) = x.cast (by rw [Nat.mul_one]) := by
|
||||
@@ -5344,7 +5378,6 @@ theorem append_assoc {x₁ : BitVec w₁} {x₂ : BitVec w₂} {x₃ : BitVec w
|
||||
theorem append_assoc' {x₁ : BitVec w₁} {x₂ : BitVec w₂} {x₃ : BitVec w₃} :
|
||||
(x₁ ++ (x₂ ++ x₃)) = ((x₁ ++ x₂) ++ x₃).cast (by omega) := by simp [append_assoc]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
theorem replicate_append_self {x : BitVec w} :
|
||||
x ++ x.replicate n = (x.replicate n ++ x).cast (by omega) := by
|
||||
induction n with
|
||||
|
||||
@@ -636,7 +636,7 @@ def boolPredToPred : Coe (α → Bool) (α → Prop) where
|
||||
This should not be turned on globally as an instance because it degrades performance in Mathlib,
|
||||
but may be used locally.
|
||||
-/
|
||||
@[expose, instance_reducible] def boolRelToRel : Coe (α → α → Bool) (α → α → Prop) where
|
||||
@[expose, implicit_reducible] def boolRelToRel : Coe (α → α → Bool) (α → α → Prop) where
|
||||
coe r := fun a b => Eq (r a b) true
|
||||
|
||||
/-! ### subtypes -/
|
||||
|
||||
@@ -50,7 +50,7 @@ instance ltTrans : Trans (· < · : Char → Char → Prop) (· < ·) (· < ·)
|
||||
trans := Char.lt_trans
|
||||
|
||||
-- This instance is useful while setting up instances for `String`.
|
||||
@[instance_reducible]
|
||||
@[implicit_reducible]
|
||||
def notLTTrans : Trans (¬ · < · : Char → Char → Prop) (¬ · < ·) (¬ · < ·) where
|
||||
trans h₁ h₂ := by simpa using Char.le_trans (by simpa using h₂) (by simpa using h₁)
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ theorem foldlM_add [Monad m] [LawfulMonad m] (f : α → Fin (n + k) → m α) :
|
||||
simp
|
||||
| succ k ih =>
|
||||
funext x
|
||||
simp [foldlM_succ_last, ← Nat.add_assoc, ih]; rfl
|
||||
simp [foldlM_succ_last, ← Nat.add_assoc, ih]
|
||||
|
||||
/-! ### foldrM -/
|
||||
|
||||
@@ -222,7 +222,7 @@ theorem foldrM_add [Monad m] [LawfulMonad m] (f : Fin (n + k) → α → m α) :
|
||||
simp
|
||||
| succ k ih =>
|
||||
funext x
|
||||
simp [foldrM_succ_last, ← Nat.add_assoc, ih]; rfl
|
||||
simp [foldrM_succ_last, ← Nat.add_assoc, ih]
|
||||
|
||||
/-! ### foldl -/
|
||||
|
||||
@@ -268,7 +268,7 @@ theorem foldl_add (f : α → Fin (n + m) → α) (x) :
|
||||
(foldl n (fun x i => f x (i.castLE (Nat.le_add_right n m))) x):= by
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih => simp [foldl_succ_last, ih, ← Nat.add_assoc]; rfl
|
||||
| succ m ih => simp [foldl_succ_last, ih, ← Nat.add_assoc]
|
||||
|
||||
theorem foldl_eq_foldlM (f : α → Fin n → α) (x) :
|
||||
foldl n f x = (foldlM (m := Id) n (pure <| f · ·) x).run := by
|
||||
@@ -321,7 +321,7 @@ theorem foldr_add (f : Fin (n + m) → α → α) (x) :
|
||||
(foldr m (fun i => f (i.natAdd n)) x) := by
|
||||
induction m generalizing x with
|
||||
| zero => simp
|
||||
| succ m ih => simp [foldr_succ_last, ih, ← Nat.add_assoc]; rfl
|
||||
| succ m ih => simp [foldr_succ_last, ih, ← Nat.add_assoc]
|
||||
|
||||
theorem foldr_eq_foldrM (f : Fin n → α → α) (x) :
|
||||
foldr n f x = (foldrM (m := Id) n (pure <| f · ·) x).run := by
|
||||
|
||||
@@ -69,7 +69,7 @@ private theorem hIterateFrom_elim {P : Nat → Sort _}(Q : ∀(i : Nat), P i →
|
||||
have g : ¬ (i < n) := by simp at p; simp [p]
|
||||
have r : Q n (_root_.cast (congrArg P p) s) :=
|
||||
@Eq.rec Nat i (fun k eq => Q k (_root_.cast (congrArg P eq) s)) init n p
|
||||
simp only [g, r, dite_false]
|
||||
simp only [g, dite_false]; exact r
|
||||
| succ j inv =>
|
||||
unfold hIterateFrom
|
||||
have d : Nat.succ i + j = n := by simp [Nat.succ_add]; exact p
|
||||
|
||||
@@ -123,7 +123,7 @@ For example, for `x : Fin k` and `n : Nat`,
|
||||
it causes `x < n` to be elaborated as `x < ↑n` rather than `↑x < n`,
|
||||
silently introducing wraparound arithmetic.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
def instNatCast (n : Nat) [NeZero n] : NatCast (Fin n) where
|
||||
natCast a := Fin.ofNat n a
|
||||
|
||||
@@ -145,7 +145,7 @@ This is not a global instance, but may be activated locally via `open Fin.IntCas
|
||||
|
||||
See the doc-string for `Fin.NatCast.instNatCast` for more details.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
def instIntCast (n : Nat) [NeZero n] : IntCast (Fin n) where
|
||||
intCast := Fin.intCast
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ Renders a `Format` to a string.
|
||||
-/
|
||||
def pretty (f : Format) (width : Nat := defWidth) (indent : Nat := 0) (column := 0) : String :=
|
||||
let act : StateM State Unit := prettyM f width indent
|
||||
State.out <| act (State.mk "" column) |>.snd
|
||||
State.out <| act.run (State.mk "" column) |>.snd
|
||||
|
||||
end Format
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.String.PosRaw
|
||||
import Init.Data.Array.Basic
|
||||
public import Init.Data.UInt.Basic
|
||||
|
||||
public section
|
||||
@@ -15,9 +15,6 @@ universe u
|
||||
instance : Hashable Nat where
|
||||
hash n := UInt64.ofNat n
|
||||
|
||||
instance : Hashable String.Pos.Raw where
|
||||
hash p := UInt64.ofNat p.byteIdx
|
||||
|
||||
instance [Hashable α] [Hashable β] : Hashable (α × β) where
|
||||
hash | (a, b) => mixHash (hash a) (hash b)
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ of another state. Having this proof bundled up with the step is important for te
|
||||
See `IterM.Step` and `Iter.Step` for the concrete choice of the plausibility predicate.
|
||||
-/
|
||||
@[expose]
|
||||
def PlausibleIterStep (IsPlausibleStep : IterStep α β → Prop) := Subtype IsPlausibleStep
|
||||
abbrev PlausibleIterStep (IsPlausibleStep : IterStep α β → Prop) := Subtype IsPlausibleStep
|
||||
|
||||
/--
|
||||
Match pattern for the `yield` case. See also `IterStep.yield`.
|
||||
@@ -379,6 +379,8 @@ class Iterator (α : Type w) (m : Type w → Type w') (β : outParam (Type w)) w
|
||||
-/
|
||||
step : (it : IterM (α := α) m β) → m (Shrink <| PlausibleIterStep <| IsPlausibleStep it)
|
||||
|
||||
attribute [reducible] Iterator.IsPlausibleStep
|
||||
|
||||
section Monadic
|
||||
|
||||
/-- The constructor has been renamed. -/
|
||||
@@ -424,7 +426,6 @@ theorem IterM.toIter_mk {α β} {it : α} :
|
||||
Asserts that certain step is plausibly the successor of a given iterator. What "plausible" means
|
||||
is up to the `Iterator` instance but it should be strong enough to allow termination proofs.
|
||||
-/
|
||||
@[expose]
|
||||
abbrev IterM.IsPlausibleStep {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β] :
|
||||
IterM (α := α) m β → IterStep (IterM (α := α) m β) β → Prop :=
|
||||
Iterator.IsPlausibleStep (α := α) (m := m)
|
||||
@@ -493,7 +494,7 @@ Asserts that certain step is plausibly the successor of a given iterator. What "
|
||||
is up to the `Iterator` instance but it should be strong enough to allow termination proofs.
|
||||
-/
|
||||
@[expose]
|
||||
def Iter.IsPlausibleStep {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
abbrev Iter.IsPlausibleStep {α : Type w} {β : Type w} [Iterator α Id β]
|
||||
(it : Iter (α := α) β) (step : IterStep (Iter (α := α) β) β) : Prop :=
|
||||
it.toIterM.IsPlausibleStep (step.mapIterator Iter.toIterM)
|
||||
|
||||
@@ -549,7 +550,7 @@ The type of the step object returned by `Iter.step`, containing an `IterStep`
|
||||
and a proof that this is a plausible step for the given iterator.
|
||||
-/
|
||||
@[expose]
|
||||
def Iter.Step {α : Type w} {β : Type w} [Iterator α Id β] (it : Iter (α := α) β) :=
|
||||
abbrev Iter.Step {α : Type w} {β : Type w} [Iterator α Id β] (it : Iter (α := α) β) :=
|
||||
PlausibleIterStep (Iter.IsPlausibleStep it)
|
||||
|
||||
/--
|
||||
|
||||
@@ -750,7 +750,6 @@ theorem Iter.anyM_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
simp only [filterMapM_eq_toIter_filterMapM_toIterM, IterM.anyM_filterMapM]
|
||||
rfl
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
-- There is hope to generalize the following theorem as soon there is a `Shrink` type.
|
||||
/--
|
||||
This lemma expresses `Iter.anyM` in terms of `IterM.anyM`.
|
||||
@@ -766,6 +765,7 @@ theorem Iter.anyM_eq_anyM_mapM_pure {α β : Type} {m : Type → Type w'} [Itera
|
||||
rw [forIn_eq_match_step, IterM.forIn_eq_match_step, bind_assoc, step_mapM]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
· rename_i out _
|
||||
simp only
|
||||
simp only [bind_assoc, pure_bind, map_eq_pure_bind, Shrink.inflate_deflate,
|
||||
liftM, monadLift]
|
||||
have {x : m Bool} : x = MonadAttach.attach (pure out) >>= (fun _ => x) := by
|
||||
@@ -778,7 +778,7 @@ theorem Iter.anyM_eq_anyM_mapM_pure {α β : Type} {m : Type → Type w'} [Itera
|
||||
apply bind_congr; intro px
|
||||
split
|
||||
· simp
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihy ‹_›, monadLift]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
|
||||
@@ -182,11 +182,12 @@ theorem IterM.step_filterMap [Monad m] [LawfulMonad m] {f : β → Option β'} :
|
||||
pure <| .deflate <| .skip (it'.filterMap f) (.skip h)
|
||||
| .done h =>
|
||||
pure <| .deflate <| .done (.done h)) := by
|
||||
simp only [IterM.filterMap, step_filterMapWithPostcondition, pure]
|
||||
simp only [IterM.filterMap]
|
||||
simp only [step_filterMapWithPostcondition, PostconditionT.operation_pure]
|
||||
apply bind_congr
|
||||
intro step
|
||||
split
|
||||
· simp only [PostconditionT.pure, PlausibleIterStep.skip, PlausibleIterStep.yield, pure_bind]
|
||||
· simp only [PlausibleIterStep.skip, PlausibleIterStep.yield, pure_bind]
|
||||
split <;> split <;> simp_all
|
||||
· simp
|
||||
· simp
|
||||
@@ -361,8 +362,8 @@ theorem IterM.toList_map_eq_toList_mapM {α β γ : Type w}
|
||||
bind_map_left]
|
||||
conv => rhs; rhs; ext a; rw [← pure_bind (x := a.val) (f := fun _ => _ <$> _)]
|
||||
simp only [← bind_assoc, bind_pure_comp, WeaklyLawfulMonadAttach.map_attach]
|
||||
simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
simpa using ihy ‹_›
|
||||
· simpa using ihs ‹_›
|
||||
· simp
|
||||
|
||||
theorem IterM.toList_map_eq_toList_filterMapM {α β γ : Type w} {m : Type w → Type w'}
|
||||
@@ -373,6 +374,7 @@ theorem IterM.toList_map_eq_toList_filterMapM {α β γ : Type w} {m : Type w
|
||||
simp [toList_map_eq_toList_mapM, toList_mapM_eq_toList_filterMapM]
|
||||
congr <;> simp
|
||||
|
||||
set_option backward.whnf.reducibleClassField false in
|
||||
/--
|
||||
Variant of `toList_filterMapWithPostcondition_filterMapWithPostcondition` that is intended to be
|
||||
used with the `apply` tactic. Because neither the LHS nor the RHS determine all implicit parameters,
|
||||
|
||||
@@ -26,7 +26,6 @@ theorem Iter.uLift_eq_toIter_uLift_toIterM {it : Iter (α := α) β} :
|
||||
it.uLift = (it.toIterM.uLift Id).toIter :=
|
||||
rfl
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
theorem Iter.step_uLift [Iterator α Id β] {it : Iter (α := α) β} :
|
||||
it.uLift.step = match it.step with
|
||||
| .yield it' out h => .yield it'.uLift (.up out) ⟨_, h, rfl⟩
|
||||
@@ -39,12 +38,11 @@ theorem Iter.step_uLift [Iterator α Id β] {it : Iter (α := α) β} :
|
||||
PlausibleIterStep.done, pure_bind]
|
||||
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp]
|
||||
theorem Iter.toList_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[Finite α Id] :
|
||||
it.uLift.toList = it.toList.map ULift.up := by
|
||||
simp only [monadLift, uLift_eq_toIter_uLift_toIterM, IterM.toList_toIter]
|
||||
simp only [uLift_eq_toIter_uLift_toIterM, IterM.toList_toIter]
|
||||
rw [IterM.toList_uLift]
|
||||
simp [monadLift, Iter.toList_eq_toList_toIterM]
|
||||
|
||||
@@ -61,12 +59,11 @@ theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
rw [← toArray_toList, ← toArray_toList, toList_uLift]
|
||||
simp [-toArray_toList]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp]
|
||||
theorem Iter.length_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] :
|
||||
it.uLift.length = it.length := by
|
||||
simp only [monadLift, uLift_eq_toIter_uLift_toIterM, length_eq_length_toIterM, toIterM_toIter]
|
||||
simp only [uLift_eq_toIter_uLift_toIterM, length_eq_length_toIterM, toIterM_toIter]
|
||||
rw [IterM.length_uLift]
|
||||
simp [monadLift]
|
||||
|
||||
|
||||
@@ -58,8 +58,7 @@ theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
forIn' ita b f = forIn' itb b' g := by
|
||||
subst_eqs
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
rfl
|
||||
rw [← h]; rfl
|
||||
|
||||
@[congr] theorem Iter.forIn_congr {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
|
||||
@@ -276,8 +275,7 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = ForIn'.forIn' it.toList init (fun out h acc => f out (Iter.mem_toList_iff_isPlausibleIndirectOutput.mp h) acc) := by
|
||||
simp only [forIn'_toList]
|
||||
congr
|
||||
simp only [forIn'_toList]; rfl
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
@@ -287,8 +285,7 @@ theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = ForIn'.forIn' it.toArray init (fun out h acc => f out (Iter.mem_toArray_iff_isPlausibleIndirectOutput.mp h) acc) := by
|
||||
simp only [forIn'_toArray]
|
||||
congr
|
||||
simp only [forIn'_toArray]; rfl
|
||||
|
||||
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
|
||||
@@ -23,7 +23,6 @@ open Std Std.Iterators
|
||||
|
||||
variable {β : Type w}
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
@[simp]
|
||||
theorem List.step_iter_nil :
|
||||
(([] : List β).iter).step = ⟨.done, rfl⟩ := by
|
||||
@@ -32,7 +31,7 @@ theorem List.step_iter_nil :
|
||||
@[simp]
|
||||
theorem List.step_iter_cons {x : β} {xs : List β} :
|
||||
((x :: xs).iter).step = ⟨.yield xs.iter x, rfl⟩ := by
|
||||
simp [List.iter, List.iterM, IterM.toIter, Iter.step_eq]; rfl
|
||||
simp [List.iter, List.iterM, IterM.toIter, Iter.step_eq]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem List.toArray_iter {l : List β} :
|
||||
|
||||
@@ -31,7 +31,7 @@ theorem List.step_iterM_nil :
|
||||
@[simp]
|
||||
theorem List.step_iterM_cons {x : β} {xs : List β} :
|
||||
((x :: xs).iterM m).step = pure (.deflate ⟨.yield (xs.iterM m) x, rfl⟩) := by
|
||||
simp only [List.iterM, IterM.step, Iterator.step]; rfl
|
||||
simp only [List.iterM, IterM.step, Iterator.step]
|
||||
|
||||
theorem List.step_iterM {l : List β} :
|
||||
(l.iterM m).step = match l with
|
||||
|
||||
@@ -70,7 +70,7 @@ private def ListIterator.instFinitenessRelation [Pure m] :
|
||||
subrelation {it it'} h := by
|
||||
simp_wf
|
||||
obtain ⟨step, h, h'⟩ := h
|
||||
cases step <;> simp_all [IterStep.successor, IterM.IsPlausibleStep, Iterator.IsPlausibleStep]
|
||||
cases step <;> simp_all [IterStep.successor, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, instIterator]
|
||||
|
||||
instance ListIterator.instFinite [Pure m] : Finite (ListIterator α) m :=
|
||||
by exact Finite.of_finitenessRelation ListIterator.instFinitenessRelation
|
||||
|
||||
@@ -32,14 +32,14 @@ def ToIterator.iter [ToIterator γ Id α β] (x : γ) : Iter (α := α) β :=
|
||||
ToIterator.iterM x |>.toIter
|
||||
|
||||
/-- Creates a monadic `ToIterator` instance. -/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline, expose, instance_reducible]
|
||||
def ToIterator.ofM (α : Type w)
|
||||
(iterM : γ → IterM (α := α) m β) :
|
||||
ToIterator γ m α β where
|
||||
iterMInternal x := iterM x
|
||||
|
||||
/-- Creates a pure `ToIterator` instance. -/
|
||||
@[always_inline, inline, expose]
|
||||
@[always_inline, inline, expose, instance_reducible]
|
||||
def ToIterator.of (α : Type w)
|
||||
(iter : γ → Iter (α := α) β) :
|
||||
ToIterator γ Id α β where
|
||||
|
||||
@@ -36,3 +36,5 @@ public import Init.Data.List.FinRange
|
||||
public import Init.Data.List.Lex
|
||||
public import Init.Data.List.Range
|
||||
public import Init.Data.List.Scan
|
||||
public import Init.Data.List.ControlImpl
|
||||
public import Init.Data.List.SplitOn
|
||||
|
||||
@@ -135,7 +135,11 @@ protected def beq [BEq α] : List α → List α → Bool
|
||||
@[simp] theorem beq_nil_nil [BEq α] : List.beq ([] : List α) ([] : List α) = true := rfl
|
||||
@[simp] theorem beq_cons_nil [BEq α] {a : α} {as : List α} : List.beq (a::as) [] = false := rfl
|
||||
@[simp] theorem beq_nil_cons [BEq α] {a : α} {as : List α} : List.beq [] (a::as) = false := rfl
|
||||
theorem beq_cons₂ [BEq α] {a b : α} {as bs : List α} : List.beq (a::as) (b::bs) = (a == b && List.beq as bs) := rfl
|
||||
theorem beq_cons_cons [BEq α] {a b : α} {as bs : List α} : List.beq (a::as) (b::bs) = (a == b && List.beq as bs) := rfl
|
||||
|
||||
@[deprecated beq_cons_cons (since := "2026-02-26")]
|
||||
theorem beq_cons₂ [BEq α] {a b : α} {as bs : List α} :
|
||||
List.beq (a::as) (b::bs) = (a == b && List.beq as bs) := beq_cons_cons
|
||||
|
||||
instance [BEq α] : BEq (List α) := ⟨List.beq⟩
|
||||
|
||||
@@ -175,7 +179,10 @@ Examples:
|
||||
@[simp, grind =] theorem isEqv_nil_nil : isEqv ([] : List α) [] eqv = true := rfl
|
||||
@[simp, grind =] theorem isEqv_nil_cons : isEqv ([] : List α) (a::as) eqv = false := rfl
|
||||
@[simp, grind =] theorem isEqv_cons_nil : isEqv (a::as : List α) [] eqv = false := rfl
|
||||
@[grind =] theorem isEqv_cons₂ : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv) := rfl
|
||||
@[grind =] theorem isEqv_cons_cons : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv) := rfl
|
||||
|
||||
@[deprecated isEqv_cons_cons (since := "2026-02-26")]
|
||||
theorem isEqv_cons₂ : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv) := isEqv_cons_cons
|
||||
|
||||
|
||||
/-! ## Lexicographic ordering -/
|
||||
@@ -1048,9 +1055,12 @@ def dropLast {α} : List α → List α
|
||||
@[simp, grind =] theorem dropLast_nil : ([] : List α).dropLast = [] := rfl
|
||||
@[simp, grind =] theorem dropLast_singleton : [x].dropLast = [] := rfl
|
||||
|
||||
@[simp, grind =] theorem dropLast_cons₂ :
|
||||
@[simp, grind =] theorem dropLast_cons_cons :
|
||||
(x::y::zs).dropLast = x :: (y::zs).dropLast := rfl
|
||||
|
||||
@[deprecated dropLast_cons_cons (since := "2026-02-26")]
|
||||
theorem dropLast_cons₂ : (x::y::zs).dropLast = x :: (y::zs).dropLast := dropLast_cons_cons
|
||||
|
||||
-- Later this can be proved by `simp` via `[List.length_dropLast, List.length_cons, Nat.add_sub_cancel]`,
|
||||
-- but we need this while bootstrapping `Array`.
|
||||
@[simp] theorem length_dropLast_cons {a : α} {as : List α} : (a :: as).dropLast.length = as.length := by
|
||||
@@ -1085,7 +1095,11 @@ inductive Sublist {α} : List α → List α → Prop
|
||||
/-- If `l₁` is a subsequence of `l₂`, then it is also a subsequence of `a :: l₂`. -/
|
||||
| cons a : Sublist l₁ l₂ → Sublist l₁ (a :: l₂)
|
||||
/-- If `l₁` is a subsequence of `l₂`, then `a :: l₁` is a subsequence of `a :: l₂`. -/
|
||||
| cons₂ a : Sublist l₁ l₂ → Sublist (a :: l₁) (a :: l₂)
|
||||
| cons_cons a : Sublist l₁ l₂ → Sublist (a :: l₁) (a :: l₂)
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated Sublist.cons_cons (since := "2026-02-26"), match_pattern]
|
||||
abbrev Sublist.cons₂ := @Sublist.cons_cons
|
||||
|
||||
@[inherit_doc] scoped infixl:50 " <+ " => Sublist
|
||||
|
||||
@@ -1143,9 +1157,13 @@ def isPrefixOf [BEq α] : List α → List α → Bool
|
||||
@[simp, grind =] theorem isPrefixOf_nil_left [BEq α] : isPrefixOf ([] : List α) l = true := by
|
||||
simp [isPrefixOf]
|
||||
@[simp, grind =] theorem isPrefixOf_cons_nil [BEq α] : isPrefixOf (a::as) ([] : List α) = false := rfl
|
||||
@[grind =] theorem isPrefixOf_cons₂ [BEq α] {a : α} :
|
||||
@[grind =] theorem isPrefixOf_cons_cons [BEq α] {a : α} :
|
||||
isPrefixOf (a::as) (b::bs) = (a == b && isPrefixOf as bs) := rfl
|
||||
|
||||
@[deprecated isPrefixOf_cons_cons (since := "2026-02-26")]
|
||||
theorem isPrefixOf_cons₂ [BEq α] {a : α} :
|
||||
isPrefixOf (a::as) (b::bs) = (a == b && isPrefixOf as bs) := isPrefixOf_cons_cons
|
||||
|
||||
/--
|
||||
If the first list is a prefix of the second, returns the result of dropping the prefix.
|
||||
|
||||
@@ -2164,10 +2182,16 @@ def intersperse (sep : α) : (l : List α) → List α
|
||||
| x::xs => x :: sep :: intersperse sep xs
|
||||
|
||||
@[simp] theorem intersperse_nil {sep : α} : ([] : List α).intersperse sep = [] := rfl
|
||||
@[simp] theorem intersperse_single {x : α} {sep : α} : [x].intersperse sep = [x] := rfl
|
||||
@[simp] theorem intersperse_cons₂ {x : α} {y : α} {zs : List α} {sep : α} :
|
||||
@[simp] theorem intersperse_singleton {x : α} {sep : α} : [x].intersperse sep = [x] := rfl
|
||||
@[deprecated intersperse_singleton (since := "2026-02-26")]
|
||||
theorem intersperse_single {x : α} {sep : α} : [x].intersperse sep = [x] := rfl
|
||||
@[simp] theorem intersperse_cons_cons {x : α} {y : α} {zs : List α} {sep : α} :
|
||||
(x::y::zs).intersperse sep = x::sep::((y::zs).intersperse sep) := rfl
|
||||
|
||||
@[deprecated intersperse_cons_cons (since := "2026-02-26")]
|
||||
theorem intersperse_cons₂ {x : α} {y : α} {zs : List α} {sep : α} :
|
||||
(x::y::zs).intersperse sep = x::sep::((y::zs).intersperse sep) := intersperse_cons_cons
|
||||
|
||||
/-! ### intercalate -/
|
||||
|
||||
set_option linter.listVariables false in
|
||||
@@ -2186,7 +2210,7 @@ Examples:
|
||||
* `List.intercalate sep [a, b] = a ++ sep ++ b`
|
||||
* `List.intercalate sep [a, b, c] = a ++ sep ++ b ++ sep ++ c`
|
||||
-/
|
||||
def intercalate (sep : List α) (xs : List (List α)) : List α :=
|
||||
noncomputable def intercalate (sep : List α) (xs : List (List α)) : List α :=
|
||||
(intersperse sep xs).flatten
|
||||
|
||||
/-! ### eraseDupsBy -/
|
||||
|
||||
@@ -219,9 +219,9 @@ def filterMapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f
|
||||
Applies a monadic function that returns a list to each element of a list, from left to right, and
|
||||
concatenates the resulting lists.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def flatMapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (List β)) (as : List α) : m (List β) :=
|
||||
let rec @[specialize] loop
|
||||
@[expose]
|
||||
noncomputable def flatMapM {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (List β)) (as : List α) : m (List β) :=
|
||||
let rec loop
|
||||
| [], bs => pure bs.reverse.flatten
|
||||
| a :: as, bs => do
|
||||
let bs' ← f a
|
||||
|
||||
35
src/Init/Data/List/ControlImpl.lean
Normal file
35
src/Init/Data/List/ControlImpl.lean
Normal file
@@ -0,0 +1,35 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Control
|
||||
public import Init.Data.List.Impl
|
||||
|
||||
public section
|
||||
|
||||
namespace List
|
||||
|
||||
/--
|
||||
Applies a monadic function that returns a list to each element of a list, from left to right, and
|
||||
concatenates the resulting lists.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def flatMapMTR {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (List β)) (as : List α) : m (List β) :=
|
||||
let rec @[specialize] loop
|
||||
| [], bs => pure bs.reverse.flatten
|
||||
| a :: as, bs => do
|
||||
let bs' ← f a
|
||||
loop as (bs' :: bs)
|
||||
loop as []
|
||||
|
||||
@[csimp] theorem flatMapM_eq_flatMapMTR : @flatMapM = @flatMapMTR := by
|
||||
funext m _ α β f l
|
||||
simp only [flatMapM, flatMapMTR]
|
||||
generalize [] = m
|
||||
fun_induction flatMapM.loop <;> simp_all [flatMapMTR.loop]
|
||||
|
||||
end List
|
||||
@@ -125,7 +125,7 @@ protected theorem Sublist.eraseP : l₁ <+ l₂ → l₁.eraseP p <+ l₂.eraseP
|
||||
by_cases h : p a
|
||||
· simpa [h] using s.eraseP.trans eraseP_sublist
|
||||
· simpa [h] using s.eraseP.cons _
|
||||
| .cons₂ a s => by
|
||||
| .cons_cons a s => by
|
||||
by_cases h : p a
|
||||
· simpa [h] using s
|
||||
· simpa [h] using s.eraseP
|
||||
|
||||
@@ -184,7 +184,7 @@ theorem Sublist.findSome?_isSome {l₁ l₂ : List α} (h : l₁ <+ l₂) :
|
||||
induction h with
|
||||
| slnil => simp
|
||||
| cons a h ih
|
||||
| cons₂ a h ih =>
|
||||
| cons_cons a h ih =>
|
||||
simp only [findSome?]
|
||||
split
|
||||
· simp_all
|
||||
@@ -455,7 +455,7 @@ theorem Sublist.find?_isSome {l₁ l₂ : List α} (h : l₁ <+ l₂) : (l₁.fi
|
||||
induction h with
|
||||
| slnil => simp
|
||||
| cons a h ih
|
||||
| cons₂ a h ih =>
|
||||
| cons_cons a h ih =>
|
||||
simp only [find?]
|
||||
split
|
||||
· simp
|
||||
|
||||
@@ -1394,7 +1394,7 @@ theorem head_filter_of_pos {p : α → Bool} {l : List α} (w : l ≠ []) (h : p
|
||||
|
||||
@[simp] theorem filter_sublist {p : α → Bool} : ∀ {l : List α}, filter p l <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => by rw [filter]; split <;> simp [Sublist.cons, Sublist.cons₂, filter_sublist]
|
||||
| a :: l => by rw [filter]; split <;> simp [Sublist.cons, Sublist.cons_cons, filter_sublist]
|
||||
|
||||
/-! ### filterMap -/
|
||||
|
||||
@@ -1838,6 +1838,11 @@ theorem sum_append [Add α] [Zero α] [Std.LawfulLeftIdentity (α := α) (· +
|
||||
[Std.Associative (α := α) (· + ·)] {l₁ l₂ : List α} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
|
||||
induction l₁ generalizing l₂ <;> simp_all [Std.Associative.assoc, Std.LawfulLeftIdentity.left_id]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_singleton [Add α] [Zero α] [Std.LawfulRightIdentity (· + ·) (0 : α)] {x : α} :
|
||||
[x].sum = x := by
|
||||
simp [List.sum_eq_foldr, Std.LawfulRightIdentity.right_id x]
|
||||
|
||||
@[simp, grind =]
|
||||
theorem sum_reverse [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.Commutative (α := α) (· + ·)]
|
||||
@@ -2727,6 +2732,31 @@ theorem foldr_assoc {op : α → α → α} [ha : Std.Associative op] :
|
||||
simp only [foldr_cons, ha.assoc]
|
||||
rw [foldr_assoc]
|
||||
|
||||
theorem foldl_eq_apply_foldr {xs : List α} {f : α → α → α}
|
||||
[Std.Associative f] [Std.LawfulRightIdentity f init] :
|
||||
xs.foldl f x = f x (xs.foldr f init) := by
|
||||
induction xs generalizing x
|
||||
· simp [Std.LawfulRightIdentity.right_id]
|
||||
· simp [foldl_assoc, *]
|
||||
|
||||
theorem foldr_eq_apply_foldl {xs : List α} {f : α → α → α}
|
||||
[Std.Associative f] [Std.LawfulLeftIdentity f init] :
|
||||
xs.foldr f x = f (xs.foldl f init) x := by
|
||||
have : Std.Associative (fun x y => f y x) := ⟨by simp [Std.Associative.assoc]⟩
|
||||
have : Std.RightIdentity (fun x y => f y x) init := ⟨⟩
|
||||
have : Std.LawfulRightIdentity (fun x y => f y x) init := ⟨by simp [Std.LawfulLeftIdentity.left_id]⟩
|
||||
rw [← List.reverse_reverse (as := xs), foldr_reverse, foldl_eq_apply_foldr, foldl_reverse]
|
||||
|
||||
theorem foldr_eq_foldl {xs : List α} {f : α → α → α}
|
||||
[Std.Associative f] [Std.LawfulIdentity f init] :
|
||||
xs.foldr f init = xs.foldl f init := by
|
||||
simp [foldl_eq_apply_foldr, Std.LawfulLeftIdentity.left_id]
|
||||
|
||||
theorem sum_eq_foldl [Zero α] [Add α] [Std.Associative (α := α) (· + ·)]
|
||||
[Std.LawfulIdentity (· + ·) (0 : α)] {xs : List α} :
|
||||
xs.sum = xs.foldl (init := 0) (· + ·) := by
|
||||
simp [sum_eq_foldr, foldl_eq_apply_foldr, Std.LawfulLeftIdentity.left_id]
|
||||
|
||||
-- The argument `f : α₁ → α₂` is intentionally explicit, as it is sometimes not found by unification.
|
||||
theorem foldl_hom (f : α₁ → α₂) {g₁ : α₁ → β → α₁} {g₂ : α₂ → β → α₂} {l : List β} {init : α₁}
|
||||
(H : ∀ x y, g₂ (f x) y = f (g₁ x y)) : l.foldl g₂ (f init) = f (l.foldl g₁ init) := by
|
||||
@@ -3124,7 +3154,7 @@ theorem dropLast_concat_getLast : ∀ {l : List α} (h : l ≠ []), dropLast l +
|
||||
| [], h => absurd rfl h
|
||||
| [_], _ => rfl
|
||||
| _ :: b :: l, _ => by
|
||||
rw [dropLast_cons₂, cons_append, getLast_cons (cons_ne_nil _ _)]
|
||||
rw [dropLast_cons_cons, cons_append, getLast_cons (cons_ne_nil _ _)]
|
||||
congr
|
||||
exact dropLast_concat_getLast (cons_ne_nil b l)
|
||||
|
||||
@@ -3525,7 +3555,7 @@ theorem getElem?_insert_succ {l : List α} {a : α} {i : Nat} :
|
||||
· split
|
||||
· rfl
|
||||
· have h' : i - 1 < l.length := Nat.lt_of_le_of_lt (Nat.pred_le _) h
|
||||
simp [h']; rfl
|
||||
simp [h']
|
||||
|
||||
theorem head?_insert {l : List α} {a : α} :
|
||||
(l.insert a).head? = some (if h : a ∈ l then l.head (ne_nil_of_mem h) else a) := by
|
||||
@@ -3744,4 +3774,28 @@ theorem get_mem : ∀ (l : List α) n, get l n ∈ l
|
||||
theorem mem_iff_get {a} {l : List α} : a ∈ l ↔ ∃ n, get l n = a :=
|
||||
⟨get_of_mem, fun ⟨_, e⟩ => e ▸ get_mem ..⟩
|
||||
|
||||
/-! ### `intercalate` -/
|
||||
|
||||
@[simp]
|
||||
theorem intercalate_nil {ys : List α} : ys.intercalate [] = [] := rfl
|
||||
|
||||
@[simp]
|
||||
theorem intercalate_singleton {ys xs : List α} : ys.intercalate [xs] = xs := by
|
||||
simp [intercalate]
|
||||
|
||||
@[simp]
|
||||
theorem intercalate_cons_cons {ys l l' : List α} {zs : List (List α)} :
|
||||
ys.intercalate (l :: l' :: zs) = l ++ ys ++ ys.intercalate (l' :: zs) := by
|
||||
simp [intercalate]
|
||||
|
||||
@[simp]
|
||||
theorem intercalate_cons_cons_left {ys l : List α} {x : α} {zs : List (List α)} :
|
||||
ys.intercalate ((x :: l) :: zs) = x :: ys.intercalate (l :: zs) := by
|
||||
cases zs <;> simp
|
||||
|
||||
theorem intercalate_cons_of_ne_nil {ys l : List α} {zs : List (List α)} (h : zs ≠ []) :
|
||||
ys.intercalate (l :: zs) = l ++ ys ++ ys.intercalate zs :=
|
||||
match zs, h with
|
||||
| l'::zs, _ => by simp
|
||||
|
||||
end List
|
||||
|
||||
@@ -350,7 +350,6 @@ theorem getElem?_mapIdx_go : ∀ {l : List α} {acc : Array β} {i : Nat},
|
||||
| [], acc, i => by
|
||||
simp only [mapIdx.go, getElem?_def, Array.length_toList,
|
||||
← Array.getElem_toList, length_nil, Nat.not_lt_zero, ↓reduceDIte, Option.map_none]
|
||||
rfl
|
||||
| a :: l, acc, i => by
|
||||
rw [mapIdx.go, getElem?_mapIdx_go]
|
||||
simp only [Array.size_push]
|
||||
|
||||
@@ -180,6 +180,21 @@ theorem min_singleton [Min α] {x : α} :
|
||||
[x].min (cons_ne_nil _ _) = x := by
|
||||
(rfl)
|
||||
|
||||
theorem min_cons_cons [Min α] {a b : α} {l : List α} :
|
||||
(a :: b :: l).min (by simp) = (min a b :: l).min (by simp) :=
|
||||
(rfl)
|
||||
|
||||
theorem min_cons [Min α] [Std.Associative (α := α) Min.min] {a : α} {l : List α} {h} :
|
||||
(a :: l).min h = l.min?.elim a (min a ·) :=
|
||||
match l with
|
||||
| nil => by simp
|
||||
| cons hd tl =>
|
||||
Option.some.inj ((min?_cons' (x := a) (xs := hd :: tl)).symm.trans min?_cons)
|
||||
|
||||
@[simp]
|
||||
theorem min_cons_cons_nil [Min α] {a b : α} : [a, b].min (by simp) = min a b := by
|
||||
simp [min_cons_cons]
|
||||
|
||||
theorem min?_eq_some_min [Min α] : {l : List α} → (hl : l ≠ []) →
|
||||
l.min? = some (l.min hl)
|
||||
| a::as, _ => by simp [List.min, List.min?_cons']
|
||||
@@ -388,6 +403,21 @@ theorem max_singleton [Max α] {x : α} :
|
||||
[x].max (cons_ne_nil _ _) = x := by
|
||||
(rfl)
|
||||
|
||||
theorem max_cons_cons [Max α] {a b : α} {l : List α} :
|
||||
(a :: b :: l).max (by simp) = (max a b :: l).max (by simp) :=
|
||||
(rfl)
|
||||
|
||||
theorem max_cons [Max α] [Std.Associative (α := α) Max.max] {a : α} {l : List α} {h} :
|
||||
(a :: l).max h = l.max?.elim a (max a ·) :=
|
||||
match l with
|
||||
| nil => by simp
|
||||
| cons hd tl =>
|
||||
Option.some.inj ((max?_cons' (x := a) (xs := hd :: tl)).symm.trans max?_cons)
|
||||
|
||||
@[simp]
|
||||
theorem max_cons_cons_nil [Max α] {a b : α} : [a, b].max (by simp) = max a b := by
|
||||
simp [max_cons_cons]
|
||||
|
||||
theorem max?_eq_some_max [Max α] : {l : List α} → (hl : l ≠ []) →
|
||||
l.max? = some (l.max hl)
|
||||
| a::as, _ => by simp [List.max, List.max?_cons']
|
||||
|
||||
@@ -358,11 +358,19 @@ private theorem combineMinIdxOn_lt [LE β] [DecidableLE β]
|
||||
simp only [combineMinIdxOn]
|
||||
split <;> (simp; omega)
|
||||
|
||||
private theorem combineMinIdxOn_lt' [LE β] [DecidableLE β]
|
||||
(f : α → β) {xs ys : List α} (zs : List α) {i j : Nat} (hi : i < xs.length) (hj : j < ys.length)
|
||||
(h : zs = xs ++ ys) :
|
||||
combineMinIdxOn f i j hi hj < zs.length := by
|
||||
simp only [combineMinIdxOn, h]
|
||||
split <;> (simp; omega)
|
||||
|
||||
private theorem combineMinIdxOn_assoc [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys zs : List α} {i j k : Nat} {f : α → β} (hi : i < xs.length) (hj : j < ys.length)
|
||||
(hk : k < zs.length) :
|
||||
(hk : k < zs.length) (h) :
|
||||
combineMinIdxOn f (combineMinIdxOn f i j _ _) k
|
||||
(combineMinIdxOn_lt f hi hj) hk = combineMinIdxOn f i (combineMinIdxOn f j k _ _) hi (combineMinIdxOn_lt f hj hk) := by
|
||||
(combineMinIdxOn_lt' f xys hi hj h) hk = combineMinIdxOn f i (combineMinIdxOn f j k _ _) hi (combineMinIdxOn_lt f hj hk) := by
|
||||
cases h
|
||||
open scoped Classical.Order in
|
||||
simp only [combineMinIdxOn]
|
||||
split
|
||||
@@ -410,10 +418,10 @@ private theorem minIdxOn_append_aux [LE β] [DecidableLE β]
|
||||
match xs with
|
||||
| [] => simp [minIdxOn_cons_aux (xs := ys) ‹_›]
|
||||
| z :: zs =>
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
simp +singlePass only [cons_append]
|
||||
simp only [minIdxOn_cons_aux (xs := z :: zs ++ ys) (by simp), ih (by simp),
|
||||
minIdxOn_cons_aux (xs := z :: zs) (by simp), combineMinIdxOn_assoc]
|
||||
minIdxOn_cons_aux (xs := z :: zs) (by simp)]
|
||||
rw [combineMinIdxOn_assoc (h := by simp)]
|
||||
|
||||
protected theorem minIdxOn_append [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{xs ys : List α} {f : α → β} (hxs : xs ≠ []) (hys : ys ≠ []) :
|
||||
|
||||
@@ -99,6 +99,15 @@ protected theorem minOn_cons
|
||||
| [] => simp
|
||||
| y :: xs => simp [foldl_assoc]
|
||||
|
||||
protected theorem minOn_cons_cons [LE β] [DecidableLE β] {a b : α} {l : List α} {f : α → β} :
|
||||
(a :: b :: l).minOn f (by simp) = (minOn f a b :: l).minOn f (by simp) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_cons_cons_nil [LE β] [DecidableLE β] {a b : α} {f : α → β} :
|
||||
[a, b].minOn f (by simp) = minOn f a b := by
|
||||
simp [List.minOn_cons_cons]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_id [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMin α]
|
||||
{xs : List α} (h : xs ≠ []) :
|
||||
@@ -242,6 +251,26 @@ protected theorem min_map
|
||||
rw [foldl_hom]
|
||||
simp [min_apply]
|
||||
|
||||
protected theorem minOn_eq_min [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMin α]
|
||||
[LE β] [DecidableLE β] {f : α → β} {l : List α} {h}
|
||||
(hf : ∀ a b, f a ≤ f b ↔ a ≤ b) : l.minOn f h = l.min h := by
|
||||
generalize hlen : l.length = n
|
||||
induction n generalizing l with
|
||||
| zero => simp_all
|
||||
| succ n ih =>
|
||||
match n, l, hlen with
|
||||
| 0, [_], _ => simp
|
||||
| 1, [b, c], _ => simp [_root_.minOn_eq_min (hf b c)]
|
||||
| n + 2, b :: c :: tl, _ =>
|
||||
simp [min_cons_cons, List.minOn_cons_cons, _root_.minOn_eq_min (hf b c)]
|
||||
rw [ih (by exact Nat.succ.inj ‹_›)]
|
||||
|
||||
protected theorem min_map_eq_min [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMin α]
|
||||
[Min β] [LE β] [DecidableLE β] [IsLinearPreorder β] [LawfulOrderLeftLeaningMin β]
|
||||
{f : α → β} (hf : ∀ a b, f a ≤ f b ↔ a ≤ b) {l : List α} {h : l ≠ []} :
|
||||
(l.map f).min (by simpa) = f (l.min h) := by
|
||||
rw [List.min_map h, List.minOn_eq_min hf]
|
||||
|
||||
@[simp]
|
||||
protected theorem minOn_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} (h : replicate n a ≠ []) :
|
||||
@@ -271,6 +300,17 @@ protected theorem maxOn_cons
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
exact List.minOn_cons (f := f)
|
||||
|
||||
protected theorem maxOn_cons_cons [LE β] [DecidableLE β] {a b : α} {l : List α} {f : α → β} :
|
||||
(a :: b :: l).maxOn f (by simp) = (maxOn f a b :: l).maxOn f (by simp) := by
|
||||
simp only [List.maxOn_eq_minOn, maxOn_eq_minOn]
|
||||
letI : LE β := (inferInstanceAs (LE β)).opposite
|
||||
exact List.minOn_cons_cons
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn_cons_cons_nil [LE β] [DecidableLE β] {a b : α} {f : α → β} :
|
||||
[a, b].maxOn f (by simp) = maxOn f a b := by
|
||||
simp [List.maxOn_cons_cons]
|
||||
|
||||
protected theorem min_eq_max {min : Min α} {xs : List α} {h} :
|
||||
xs.min h = (letI := min.oppositeMax; xs.max h) := by
|
||||
simp only [List.min, List.max]
|
||||
@@ -394,6 +434,26 @@ protected theorem max_map
|
||||
letI : Min β := (inferInstanceAs (Max β)).oppositeMin
|
||||
simpa [List.max_eq_min] using List.min_map (f := f) h
|
||||
|
||||
protected theorem maxOn_eq_max [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α]
|
||||
[LE β] [DecidableLE β] {f : α → β} {l : List α} {h}
|
||||
(hf : ∀ a b, f a ≤ f b ↔ a ≤ b) : l.maxOn f h = l.max h := by
|
||||
generalize hlen : l.length = n
|
||||
induction n generalizing l with
|
||||
| zero => simp_all
|
||||
| succ n ih =>
|
||||
match n, l, hlen with
|
||||
| 0, [_], _ => simp
|
||||
| 1, [b, c], _ => simp [_root_.maxOn_eq_max (hf c b)]
|
||||
| n + 2, b :: c :: tl, _ =>
|
||||
simp [max_cons_cons, List.maxOn_cons_cons, _root_.maxOn_eq_max (hf c b)]
|
||||
rw [ih (by exact Nat.succ.inj ‹_›)]
|
||||
|
||||
protected theorem max_map_eq_max [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α]
|
||||
[Max β] [LE β] [DecidableLE β] [IsLinearPreorder β] [LawfulOrderLeftLeaningMax β]
|
||||
{f : α → β} (hf : ∀ a b, f a ≤ f b ↔ a ≤ b) {l : List α} {h : l ≠ []} :
|
||||
(l.map f).max (by simpa) = f (l.max h) := by
|
||||
rw [List.max_map h, List.maxOn_eq_max hf]
|
||||
|
||||
@[simp]
|
||||
protected theorem maxOn_replicate [LE β] [DecidableLE β] [IsLinearPreorder β]
|
||||
{n : Nat} {a : α} {f : α → β} (h : replicate n a ≠ []) :
|
||||
|
||||
@@ -42,7 +42,7 @@ theorem beq_eq_isEqv [BEq α] {as bs : List α} : as.beq bs = isEqv as bs (· ==
|
||||
cases bs with
|
||||
| nil => simp
|
||||
| cons b bs =>
|
||||
simp only [beq_cons₂, ih, isEqv_eq_decide, length_cons, Nat.add_right_cancel_iff,
|
||||
simp only [beq_cons_cons, ih, isEqv_eq_decide, length_cons, Nat.add_right_cancel_iff,
|
||||
Nat.forall_lt_succ_left', getElem_cons_zero, getElem_cons_succ, Bool.decide_and,
|
||||
Bool.decide_eq_true]
|
||||
split <;> simp
|
||||
|
||||
@@ -106,7 +106,7 @@ theorem Sublist.le_countP (s : l₁ <+ l₂) (p) : countP p l₂ - (l₂.length
|
||||
have := s.le_countP p
|
||||
have := s.length_le
|
||||
split <;> omega
|
||||
| .cons₂ a s =>
|
||||
| .cons_cons a s =>
|
||||
rename_i l₁ l₂
|
||||
simp only [countP_cons, length_cons]
|
||||
have := s.le_countP p
|
||||
|
||||
@@ -38,7 +38,7 @@ theorem map_getElem_sublist {l : List α} {is : List (Fin l.length)} (h : is.Pai
|
||||
simp only [Fin.getElem_fin, map_cons]
|
||||
have := IH h.of_cons (hd+1) (pairwise_cons.mp h).1
|
||||
specialize his hd (.head _)
|
||||
have := (drop_eq_getElem_cons ..).symm ▸ this.cons₂ (get l hd)
|
||||
have := (drop_eq_getElem_cons ..).symm ▸ this.cons_cons (get l hd)
|
||||
have := Sublist.append (nil_sublist (take hd l |>.drop j)) this
|
||||
rwa [nil_append, ← (drop_append_of_le_length ?_), take_append_drop] at this
|
||||
simp [Nat.min_eq_left (Nat.le_of_lt hd.isLt), his]
|
||||
@@ -55,7 +55,7 @@ theorem sublist_eq_map_getElem {l l' : List α} (h : l' <+ l) : ∃ is : List (F
|
||||
refine ⟨is.map (·.succ), ?_⟩
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
simpa [Function.comp_def, pairwise_map]
|
||||
| cons₂ _ _ IH =>
|
||||
| cons_cons _ _ IH =>
|
||||
rcases IH with ⟨is,IH⟩
|
||||
refine ⟨⟨0, by simp [Nat.zero_lt_succ]⟩ :: is.map (·.succ), ?_⟩
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
|
||||
@@ -207,7 +207,7 @@ theorem take_eq_dropLast {l : List α} {i : Nat} (h : i + 1 = l.length) :
|
||||
· cases as with
|
||||
| nil => simp_all
|
||||
| cons b bs =>
|
||||
simp only [take_succ_cons, dropLast_cons₂]
|
||||
simp only [take_succ_cons, dropLast_cons_cons]
|
||||
rw [ih]
|
||||
simpa using h
|
||||
|
||||
|
||||
@@ -99,7 +99,6 @@ theorem ofFn_add {n m} {f : Fin (n + m) → α} :
|
||||
induction m with
|
||||
| zero => simp
|
||||
| succ m ih =>
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
simp [-ofFn_succ, ofFn_succ_last, ih]
|
||||
|
||||
@[simp]
|
||||
@@ -157,7 +156,6 @@ theorem ofFnM_add {n m} [Monad m] [LawfulMonad m] {f : Fin (n + k) → m α} :
|
||||
induction k with
|
||||
| zero => simp
|
||||
| succ k ih =>
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
simp [ofFnM_succ_last, ih]
|
||||
|
||||
end List
|
||||
|
||||
@@ -33,7 +33,7 @@ open Nat
|
||||
@[grind →] theorem Pairwise.sublist : l₁ <+ l₂ → l₂.Pairwise R → l₁.Pairwise R
|
||||
| .slnil, h => h
|
||||
| .cons _ s, .cons _ h₂ => h₂.sublist s
|
||||
| .cons₂ _ s, .cons h₁ h₂ => (h₂.sublist s).cons fun _ h => h₁ _ (s.subset h)
|
||||
| .cons_cons _ s, .cons h₁ h₂ => (h₂.sublist s).cons fun _ h => h₁ _ (s.subset h)
|
||||
|
||||
theorem Pairwise.imp {α R S} (H : ∀ {a b}, R a b → S a b) :
|
||||
∀ {l : List α}, l.Pairwise R → l.Pairwise S
|
||||
@@ -226,7 +226,7 @@ theorem pairwise_iff_forall_sublist : l.Pairwise R ↔ (∀ {a b}, [a,b] <+ l
|
||||
constructor <;> intro h
|
||||
· intro
|
||||
| a, b, .cons _ hab => exact IH.mp h.2 hab
|
||||
| _, b, .cons₂ _ hab => refine h.1 _ (hab.subset ?_); simp
|
||||
| _, b, .cons_cons _ hab => refine h.1 _ (hab.subset ?_); simp
|
||||
· constructor
|
||||
· intro x hx
|
||||
apply h
|
||||
@@ -304,26 +304,43 @@ grind_pattern Nodup.sublist => l₁ <+ l₂, Nodup l₂
|
||||
theorem Sublist.nodup : l₁ <+ l₂ → Nodup l₂ → Nodup l₁ :=
|
||||
Nodup.sublist
|
||||
|
||||
theorem getElem?_inj {xs : List α}
|
||||
(h₀ : i < xs.length) (h₁ : Nodup xs) (h₂ : xs[i]? = xs[j]?) : i = j := by
|
||||
induction xs generalizing i j with
|
||||
| nil => cases h₀
|
||||
| cons x xs ih =>
|
||||
match i, j with
|
||||
| 0, 0 => rfl
|
||||
| i+1, j+1 =>
|
||||
cases h₁ with
|
||||
| cons ha h₁ =>
|
||||
simp only [getElem?_cons_succ] at h₂
|
||||
exact congrArg (· + 1) (ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂)
|
||||
| i+1, 0 => ?_
|
||||
| 0, j+1 => ?_
|
||||
all_goals
|
||||
simp only [getElem?_cons_zero, getElem?_cons_succ] at h₂
|
||||
cases h₁; rename_i h' h
|
||||
have := h x ?_ rfl; cases this
|
||||
rw [mem_iff_getElem?]
|
||||
exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩
|
||||
theorem getElem?_inj {l : List α} (h₀ : i < l.length) (h₁ : List.Nodup l) :
|
||||
l[i]? = l[j]? ↔ i = j :=
|
||||
⟨by
|
||||
intro h₂
|
||||
induction l generalizing i j with
|
||||
| nil => cases h₀
|
||||
| cons x xs ih =>
|
||||
match i, j with
|
||||
| 0, 0 => rfl
|
||||
| i+1, j+1 =>
|
||||
cases h₁ with
|
||||
| cons ha h₁ =>
|
||||
simp only [getElem?_cons_succ] at h₂
|
||||
exact congrArg (· + 1) (ih (Nat.lt_of_succ_lt_succ h₀) h₁ h₂)
|
||||
| i+1, 0 => ?_
|
||||
| 0, j+1 => ?_
|
||||
all_goals
|
||||
simp only [getElem?_cons_zero, getElem?_cons_succ] at h₂
|
||||
cases h₁; rename_i h' h
|
||||
have := h x ?_ rfl; cases this
|
||||
rw [mem_iff_getElem?]
|
||||
exact ⟨_, h₂⟩; exact ⟨_ , h₂.symm⟩
|
||||
, by simp +contextual⟩
|
||||
|
||||
theorem getElem_inj {xs : List α}
|
||||
{h₀ : i < xs.length} {h₁ : j < xs.length} (h : Nodup xs) : xs[i] = xs[j] ↔ i = j := by
|
||||
simpa only [List.getElem_eq_getElem?_get, Option.get_inj] using getElem?_inj h₀ h
|
||||
|
||||
theorem getD_inj {xs : List α}
|
||||
(h₀ : i < xs.length) (h₁ : j < xs.length) (h₂ : Nodup xs) :
|
||||
xs.getD i fallback = xs.getD j fallback ↔ i = j := by
|
||||
simp only [List.getD_eq_getElem?_getD]
|
||||
rw [Option.getD_inj, getElem?_inj] <;> simpa
|
||||
|
||||
theorem getElem!_inj [Inhabited α] {xs : List α}
|
||||
(h₀ : i < xs.length) (h₁ : j < xs.length) (h₂ : Nodup xs) : xs[i]! = xs[j]! ↔ i = j := by
|
||||
simpa only [getElem!_eq_getElem?_getD, ← getD_eq_getElem?_getD] using getD_inj h₀ h₁ h₂
|
||||
|
||||
@[simp, grind =] theorem nodup_replicate {n : Nat} {a : α} :
|
||||
(replicate n a).Nodup ↔ n ≤ 1 := by simp [Nodup]
|
||||
|
||||
@@ -252,13 +252,13 @@ theorem exists_perm_sublist {l₁ l₂ l₂' : List α} (s : l₁ <+ l₂) (p :
|
||||
| cons x _ IH =>
|
||||
match s with
|
||||
| .cons _ s => let ⟨l₁', p', s'⟩ := IH s; exact ⟨l₁', p', s'.cons _⟩
|
||||
| .cons₂ _ s => let ⟨l₁', p', s'⟩ := IH s; exact ⟨x :: l₁', p'.cons x, s'.cons₂ _⟩
|
||||
| .cons_cons _ s => let ⟨l₁', p', s'⟩ := IH s; exact ⟨x :: l₁', p'.cons x, s'.cons_cons _⟩
|
||||
| swap x y l' =>
|
||||
match s with
|
||||
| .cons _ (.cons _ s) => exact ⟨_, .rfl, (s.cons _).cons _⟩
|
||||
| .cons _ (.cons₂ _ s) => exact ⟨x :: _, .rfl, (s.cons _).cons₂ _⟩
|
||||
| .cons₂ _ (.cons _ s) => exact ⟨y :: _, .rfl, (s.cons₂ _).cons _⟩
|
||||
| .cons₂ _ (.cons₂ _ s) => exact ⟨x :: y :: _, .swap .., (s.cons₂ _).cons₂ _⟩
|
||||
| .cons _ (.cons_cons _ s) => exact ⟨x :: _, .rfl, (s.cons _).cons_cons _⟩
|
||||
| .cons_cons _ (.cons _ s) => exact ⟨y :: _, .rfl, (s.cons_cons _).cons _⟩
|
||||
| .cons_cons _ (.cons_cons _ s) => exact ⟨x :: y :: _, .swap .., (s.cons_cons _).cons_cons _⟩
|
||||
| trans _ _ IH₁ IH₂ =>
|
||||
let ⟨_, pm, sm⟩ := IH₁ s
|
||||
let ⟨r₁, pr, sr⟩ := IH₂ sm
|
||||
@@ -277,7 +277,7 @@ theorem Sublist.exists_perm_append {l₁ l₂ : List α} : l₁ <+ l₂ → ∃
|
||||
| Sublist.cons a s =>
|
||||
let ⟨l, p⟩ := Sublist.exists_perm_append s
|
||||
⟨a :: l, (p.cons a).trans perm_middle.symm⟩
|
||||
| Sublist.cons₂ a s =>
|
||||
| Sublist.cons_cons a s =>
|
||||
let ⟨l, p⟩ := Sublist.exists_perm_append s
|
||||
⟨l, p.cons a⟩
|
||||
|
||||
|
||||
@@ -452,7 +452,7 @@ theorem sublist_mergeSort
|
||||
have h' := sublist_mergeSort trans total hc h
|
||||
rw [h₂] at h'
|
||||
exact h'.middle a
|
||||
| _, _, @Sublist.cons₂ _ l₁ l₂ a h => by
|
||||
| _, _, @Sublist.cons_cons _ l₁ l₂ a h => by
|
||||
rename_i hc
|
||||
obtain ⟨l₃, l₄, h₁, h₂, h₃⟩ := mergeSort_cons trans total a l₂
|
||||
rw [h₁]
|
||||
@@ -460,7 +460,7 @@ theorem sublist_mergeSort
|
||||
rw [h₂] at h'
|
||||
simp only [Bool.not_eq_true', tail_cons] at h₃ h'
|
||||
exact
|
||||
sublist_append_of_sublist_right (Sublist.cons₂ a
|
||||
sublist_append_of_sublist_right (Sublist.cons_cons a
|
||||
((fun w => Sublist.of_sublist_append_right w h') fun b m₁ m₃ =>
|
||||
(Bool.eq_not_self true).mp ((rel_of_pairwise_cons hc m₁).symm.trans (h₃ b m₃))))
|
||||
|
||||
|
||||
10
src/Init/Data/List/SplitOn.lean
Normal file
10
src/Init/Data/List/SplitOn.lean
Normal file
@@ -0,0 +1,10 @@
|
||||
/-
|
||||
Copyright (c) 2026 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.SplitOn.Basic
|
||||
public import Init.Data.List.SplitOn.Lemmas
|
||||
70
src/Init/Data/List/SplitOn/Basic.lean
Normal file
70
src/Init/Data/List/SplitOn/Basic.lean
Normal file
@@ -0,0 +1,70 @@
|
||||
/-
|
||||
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.Basic
|
||||
public import Init.NotationExtra
|
||||
import Init.Data.Array.Bootstrap
|
||||
import Init.Data.List.Lemmas
|
||||
|
||||
public section
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
namespace List
|
||||
|
||||
/--
|
||||
Split a list at every element satisfying a predicate, and then prepend {lean}`acc.reverse` to the
|
||||
first element of the result.
|
||||
|
||||
* {lean}`[1, 1, 2, 3, 2, 4, 4].splitOnPPrepend (· == 2) [0, 5] = [[5, 0, 1, 1], [3], [4, 4]]`
|
||||
-/
|
||||
noncomputable def splitOnPPrepend (p : α → Bool) : (l : List α) → (acc : List α) → List (List α)
|
||||
| [], acc => [acc.reverse]
|
||||
| a :: t, acc => if p a then acc.reverse :: splitOnPPrepend p t [] else splitOnPPrepend p t (a::acc)
|
||||
|
||||
/--
|
||||
Split a list at every element satisfying a predicate. The separators are not in the result.
|
||||
|
||||
Examples:
|
||||
* {lean}`[1, 1, 2, 3, 2, 4, 4].splitOnP (· == 2) = [[1, 1], [3], [4, 4]]`
|
||||
-/
|
||||
noncomputable def splitOnP (p : α → Bool) (l : List α) : List (List α) :=
|
||||
splitOnPPrepend p l []
|
||||
|
||||
@[deprecated splitOnPPrepend (since := "2026-02-26")]
|
||||
noncomputable def splitOnP.go (p : α → Bool) (l acc : List α) : List (List α) :=
|
||||
splitOnPPrepend p l acc
|
||||
|
||||
/-- Tail recursive version of {name}`splitOnP`. -/
|
||||
@[inline]
|
||||
def splitOnPTR (p : α → Bool) (l : List α) : List (List α) := go l #[] #[] where
|
||||
@[specialize] go : List α → Array α → Array (List α) → List (List α)
|
||||
| [], acc, r => r.toListAppend [acc.toList]
|
||||
| a :: t, acc, r => bif p a then go t #[] (r.push acc.toList) else go t (acc.push a) r
|
||||
|
||||
@[csimp] theorem splitOnP_eq_splitOnPTR : @splitOnP = @splitOnPTR := by
|
||||
funext α P l
|
||||
simp only [splitOnPTR]
|
||||
suffices ∀ xs acc r,
|
||||
splitOnPTR.go P xs acc r = r.toList ++ splitOnPPrepend P xs acc.toList.reverse from
|
||||
(this l #[] #[]).symm
|
||||
intro xs acc r
|
||||
induction xs generalizing acc r with
|
||||
| nil => simp [splitOnPPrepend, splitOnPTR.go]
|
||||
| cons x xs IH => cases h : P x <;> simp [splitOnPPrepend, splitOnPTR.go, *]
|
||||
|
||||
/--
|
||||
Split a list at every occurrence of a separator element. The separators are not in the result.
|
||||
|
||||
Examples:
|
||||
* {lean}`[1, 1, 2, 3, 2, 4, 4].splitOn 2 = [[1, 1], [3], [4, 4]]`
|
||||
-/
|
||||
@[inline] def splitOn [BEq α] (a : α) (as : List α) : List (List α) :=
|
||||
as.splitOnP (· == a)
|
||||
|
||||
end List
|
||||
208
src/Init/Data/List/SplitOn/Lemmas.lean
Normal file
208
src/Init/Data/List/SplitOn/Lemmas.lean
Normal file
@@ -0,0 +1,208 @@
|
||||
/-
|
||||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro, Markus Himmel
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.List.SplitOn.Basic
|
||||
import all Init.Data.List.SplitOn.Basic
|
||||
import Init.Data.List.Nat.Modify
|
||||
import Init.ByCases
|
||||
|
||||
public section
|
||||
|
||||
namespace List
|
||||
|
||||
variable {p : α → Bool} {xs : List α} {ls : List (List α)}
|
||||
|
||||
@[simp]
|
||||
theorem splitOn_nil [BEq α] (a : α) : [].splitOn a = [[]] :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem splitOnP_nil : [].splitOnP p = [[]] :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem splitOnPPrepend_ne_nil (p : α → Bool) (xs acc : List α) : splitOnPPrepend p xs acc ≠ [] := by
|
||||
fun_induction splitOnPPrepend <;> simp_all
|
||||
|
||||
@[deprecated splitOnPPrepend_ne_nil (since := "2026-02-26")]
|
||||
theorem splitOnP.go_ne_nil (p : α → Bool) (xs acc : List α) : splitOnPPrepend p xs acc ≠ [] :=
|
||||
splitOnPPrepend_ne_nil p xs acc
|
||||
|
||||
@[simp] theorem splitOnPPrepend_nil {acc : List α} : splitOnPPrepend p [] acc = [acc.reverse] := (rfl)
|
||||
@[simp] theorem splitOnPPrepend_nil_right : splitOnPPrepend p xs [] = splitOnP p xs := (rfl)
|
||||
theorem splitOnP_eq_splitOnPPrepend : splitOnP p xs = splitOnPPrepend p xs [] := (rfl)
|
||||
|
||||
theorem splitOnPPrepend_cons_eq_if {x : α} {xs acc : List α} :
|
||||
splitOnPPrepend p (x :: xs) acc =
|
||||
if p x then acc.reverse :: splitOnP p xs else splitOnPPrepend p xs (x :: acc) := by
|
||||
simp [splitOnPPrepend]
|
||||
|
||||
theorem splitOnPPrepend_cons_pos {p : α → Bool} {a : α} {l acc : List α} (h : p a) :
|
||||
splitOnPPrepend p (a :: l) acc = acc.reverse :: splitOnP p l := by
|
||||
simp [splitOnPPrepend, h]
|
||||
|
||||
theorem splitOnPPrepend_cons_neg {p : α → Bool} {a : α} {l acc : List α} (h : p a = false) :
|
||||
splitOnPPrepend p (a :: l) acc = splitOnPPrepend p l (a :: acc) := by
|
||||
simp [splitOnPPrepend, h]
|
||||
|
||||
theorem splitOnP_cons_eq_if_splitOnPPrepend {x : α} {xs : List α} :
|
||||
splitOnP p (x :: xs) = if p x then [] :: splitOnP p xs else splitOnPPrepend p xs [x] := by
|
||||
simp [splitOnPPrepend_cons_eq_if, ← splitOnPPrepend_nil_right]
|
||||
|
||||
theorem splitOnPPrepend_eq_modifyHead {xs acc : List α} :
|
||||
splitOnPPrepend p xs acc = modifyHead (acc.reverse ++ ·) (splitOnP p xs) := by
|
||||
induction xs generalizing acc with
|
||||
| nil => simp
|
||||
| cons hd tl ih =>
|
||||
simp [splitOnPPrepend_cons_eq_if, splitOnP_cons_eq_if_splitOnPPrepend, ih]
|
||||
split <;> simp <;> congr
|
||||
|
||||
@[deprecated splitOnPPrepend_eq_modifyHead (since := "2026-02-26")]
|
||||
theorem splitOnP.go_acc {xs acc : List α} :
|
||||
splitOnPPrepend p xs acc = modifyHead (acc.reverse ++ ·) (splitOnP p xs) :=
|
||||
splitOnPPrepend_eq_modifyHead
|
||||
|
||||
@[simp]
|
||||
theorem splitOnP_ne_nil (p : α → Bool) (xs : List α) : xs.splitOnP p ≠ [] :=
|
||||
splitOnPPrepend_ne_nil p xs []
|
||||
|
||||
theorem splitOnP_cons_eq_if_modifyHead (x : α) (xs : List α) :
|
||||
(x :: xs).splitOnP p =
|
||||
if p x then [] :: xs.splitOnP p else (xs.splitOnP p).modifyHead (cons x) := by
|
||||
simp [splitOnP_cons_eq_if_splitOnPPrepend, splitOnPPrepend_eq_modifyHead]
|
||||
|
||||
@[deprecated splitOnP_cons_eq_if_modifyHead (since := "2026-02-26")]
|
||||
theorem splitOnP_cons (x : α) (xs : List α) :
|
||||
(x :: xs).splitOnP p =
|
||||
if p x then [] :: xs.splitOnP p else (xs.splitOnP p).modifyHead (cons x) :=
|
||||
splitOnP_cons_eq_if_modifyHead x xs
|
||||
|
||||
/-- The original list `L` can be recovered by flattening the lists produced by `splitOnP p L`,
|
||||
interspersed with the elements `L.filter p`. -/
|
||||
theorem splitOnP_spec (as : List α) :
|
||||
flatten (zipWith (· ++ ·) (splitOnP p as) (((as.filter p).map fun x => [x]) ++ [[]])) = as := by
|
||||
induction as with
|
||||
| nil => simp
|
||||
| cons a as' ih =>
|
||||
rw [splitOnP_cons_eq_if_modifyHead]
|
||||
split <;> simp [*, flatten_zipWith, splitOnP_ne_nil]
|
||||
where
|
||||
flatten_zipWith {xs ys : List (List α)} {a : α} (hxs : xs ≠ []) (hys : ys ≠ []) :
|
||||
flatten (zipWith (fun x x_1 => x ++ x_1) (modifyHead (cons a) xs) ys) =
|
||||
a :: flatten (zipWith (fun x x_1 => x ++ x_1) xs ys) := by
|
||||
cases xs <;> cases ys <;> simp_all
|
||||
|
||||
/-- If no element satisfies `p` in the list `xs`, then `xs.splitOnP p = [xs]` -/
|
||||
theorem splitOnP_eq_singleton (h : ∀ x ∈ xs, p x = false) : xs.splitOnP p = [xs] := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons hd tl ih =>
|
||||
simp only [mem_cons, forall_eq_or_imp] at h
|
||||
simp [splitOnP_cons_eq_if_modifyHead, h.1, ih h.2]
|
||||
|
||||
@[deprecated splitOnP_eq_singleton (since := "2026-02-26")]
|
||||
theorem splitOnP_eq_single (h : ∀ x ∈ xs, p x = false) : xs.splitOnP p = [xs] :=
|
||||
splitOnP_eq_singleton h
|
||||
|
||||
/-- When a list of the form `[...xs, sep, ...as]` is split at the `sep` element satisfying `p`,
|
||||
the result is the concatenation of `splitOnP` called on `xs` and `as` -/
|
||||
theorem splitOnP_append_cons (xs as : List α) {sep : α} (hsep : p sep) :
|
||||
(xs ++ sep :: as).splitOnP p = List.splitOnP p xs ++ List.splitOnP p as := by
|
||||
induction xs with
|
||||
| nil => simp [splitOnP_cons_eq_if_modifyHead, hsep]
|
||||
| cons hd tl ih =>
|
||||
obtain ⟨hd1, tl1, h1'⟩ := List.exists_cons_of_ne_nil (List.splitOnP_ne_nil (p := p) (xs := tl))
|
||||
by_cases hPh : p hd <;> simp [splitOnP_cons_eq_if_modifyHead, *]
|
||||
|
||||
/-- When a list of the form `[...xs, sep, ...as]` is split on `p`, the first element is `xs`,
|
||||
assuming no element in `xs` satisfies `p` but `sep` does satisfy `p` -/
|
||||
theorem splitOnP_append_cons_of_forall_mem (h : ∀ x ∈ xs, p x = false) (sep : α)
|
||||
(hsep : p sep = true) (as : List α) : (xs ++ sep :: as).splitOnP p = xs :: as.splitOnP p := by
|
||||
rw [splitOnP_append_cons xs as hsep, splitOnP_eq_singleton h, singleton_append]
|
||||
|
||||
@[deprecated splitOnP_append_cons_of_forall_mem (since := "2026-02-26")]
|
||||
theorem splitOnP_first (h : ∀ x ∈ xs, p x = false) (sep : α)
|
||||
(hsep : p sep = true) (as : List α) : (xs ++ sep :: as).splitOnP p = xs :: as.splitOnP p :=
|
||||
splitOnP_append_cons_of_forall_mem h sep hsep as
|
||||
|
||||
theorem splitOn_eq_splitOnP [BEq α] {x : α} {xs : List α} : xs.splitOn x = xs.splitOnP (· == x) :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem splitOn_ne_nil [BEq α] (a : α) (xs : List α) : xs.splitOn a ≠ [] := by
|
||||
simp [splitOn_eq_splitOnP]
|
||||
|
||||
theorem splitOn_cons_eq_if_modifyHead [BEq α] {a : α} (x : α) (xs : List α) :
|
||||
(x :: xs).splitOn a =
|
||||
if x == a then [] :: xs.splitOn a else (xs.splitOn a).modifyHead (cons x) := by
|
||||
simpa [splitOn_eq_splitOnP] using splitOnP_cons_eq_if_modifyHead ..
|
||||
|
||||
/-- If no element satisfies `p` in the list `xs`, then `xs.splitOnP p = [xs]` -/
|
||||
theorem splitOn_eq_singleton_of_beq_eq_false [BEq α] {a : α} (h : ∀ x ∈ xs, (x == a) = false) :
|
||||
xs.splitOn a = [xs] := by
|
||||
simpa [splitOn_eq_splitOnP] using splitOnP_eq_singleton h
|
||||
|
||||
theorem splitOn_eq_singleton [BEq α] [LawfulBEq α] {a : α} (h : a ∉ xs) :
|
||||
xs.splitOn a = [xs] :=
|
||||
splitOn_eq_singleton_of_beq_eq_false
|
||||
(fun _ hb => beq_eq_false_iff_ne.2 (fun hab => absurd hb (hab ▸ h)))
|
||||
|
||||
/-- When a list of the form `[...xs, sep, ...as]` is split at the `sep` element equal to `a`,
|
||||
the result is the concatenation of `splitOnP` called on `xs` and `as` -/
|
||||
theorem splitOn_append_cons_of_beq [BEq α] {a : α} (xs as : List α) {sep : α} (hsep : sep == a) :
|
||||
(xs ++ sep :: as).splitOn a = List.splitOn a xs ++ List.splitOn a as := by
|
||||
simpa [splitOn_eq_splitOnP] using splitOnP_append_cons (p := (· == a)) _ _ hsep
|
||||
|
||||
/-- When a list of the form `[...xs, sep, ...as]` is split at `a`,
|
||||
the result is the concatenation of `splitOnP` called on `xs` and `as` -/
|
||||
theorem splitOn_append_cons_self [BEq α] [ReflBEq α] {a : α} (xs as : List α) :
|
||||
(xs ++ a :: as).splitOn a = List.splitOn a xs ++ List.splitOn a as :=
|
||||
splitOn_append_cons_of_beq _ _ (BEq.refl _)
|
||||
|
||||
/-- When a list of the form `[...xs, sep, ...as]` is split at `a`, the first element is `xs`,
|
||||
assuming no element in `xs` is equal to `a` but `sep` is equal to `a`. -/
|
||||
theorem splitOn_append_cons_of_forall_mem_beq_eq_false [BEq α] {a : α}
|
||||
(h : ∀ x ∈ xs, (x == a) = false) (sep : α)
|
||||
(hsep : sep == a) (as : List α) : (xs ++ sep :: as).splitOn a = xs :: as.splitOn a := by
|
||||
simpa [splitOn_eq_splitOnP] using splitOnP_append_cons_of_forall_mem h _ hsep _
|
||||
|
||||
/-- When a list of the form `[...xs, a, ...as]` is split at `a`, the first element is `xs`,
|
||||
assuming no element in `xs` is equal to `a`. -/
|
||||
theorem splitOn_append_cons_self_of_not_mem [BEq α] [LawfulBEq α] {a : α}
|
||||
(h : a ∉ xs) (as : List α) : (xs ++ a :: as).splitOn a = xs :: as.splitOn a :=
|
||||
splitOn_append_cons_of_forall_mem_beq_eq_false
|
||||
(fun b hb => beq_eq_false_iff_ne.2 fun hab => absurd hb (hab ▸ h)) _ (by simp) _
|
||||
|
||||
/-- `intercalate [x]` is the left inverse of `splitOn x` -/
|
||||
@[simp]
|
||||
theorem intercalate_splitOn [BEq α] [LawfulBEq α] (x : α) : [x].intercalate (xs.splitOn x) = xs := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons hd tl ih =>
|
||||
simp only [splitOn_cons_eq_if_modifyHead, beq_iff_eq]
|
||||
split
|
||||
· simp_all [intercalate_cons_of_ne_nil, splitOn_ne_nil]
|
||||
· have hsp := splitOn_ne_nil x tl
|
||||
generalize splitOn x tl = ls at *
|
||||
cases ls <;> simp_all
|
||||
|
||||
/-- `splitOn x` is the left inverse of `intercalate [x]`, on the domain
|
||||
consisting of each nonempty list of lists `ls` whose elements do not contain `x` -/
|
||||
theorem splitOn_intercalate [BEq α] [LawfulBEq α] (x : α) (hx : ∀ l ∈ ls, x ∉ l) (hls : ls ≠ []) :
|
||||
([x].intercalate ls).splitOn x = ls := by
|
||||
induction ls with
|
||||
| nil => simp at hls
|
||||
| cons hd tl ih =>
|
||||
simp only [mem_cons, forall_eq_or_imp] at ⊢ hx
|
||||
match tl with
|
||||
| [] => simpa using splitOn_eq_singleton hx.1
|
||||
| t::tl =>
|
||||
simp only [intercalate_cons_cons, append_assoc, cons_append, nil_append]
|
||||
rw [splitOn_append_cons_self_of_not_mem hx.1, ih hx.2 (by simp)]
|
||||
|
||||
end List
|
||||
@@ -32,8 +32,12 @@ open Nat
|
||||
section isPrefixOf
|
||||
variable [BEq α]
|
||||
|
||||
@[simp, grind =] theorem isPrefixOf_cons₂_self [LawfulBEq α] {a : α} :
|
||||
isPrefixOf (a::as) (a::bs) = isPrefixOf as bs := by simp [isPrefixOf_cons₂]
|
||||
@[simp, grind =] theorem isPrefixOf_cons_cons_self [LawfulBEq α] {a : α} :
|
||||
isPrefixOf (a::as) (a::bs) = isPrefixOf as bs := by simp [isPrefixOf_cons_cons]
|
||||
|
||||
@[deprecated isPrefixOf_cons_cons_self (since := "2026-02-26")]
|
||||
theorem isPrefixOf_cons₂_self [LawfulBEq α] {a : α} :
|
||||
isPrefixOf (a::as) (a::bs) = isPrefixOf as bs := isPrefixOf_cons_cons_self
|
||||
|
||||
@[simp] theorem isPrefixOf_length_pos_nil {l : List α} (h : 0 < l.length) : isPrefixOf l [] = false := by
|
||||
cases l <;> simp_all [isPrefixOf]
|
||||
@@ -45,7 +49,7 @@ variable [BEq α]
|
||||
| cons _ _ ih =>
|
||||
cases n
|
||||
· simp
|
||||
· simp [replicate_succ, isPrefixOf_cons₂, ih, Nat.succ_le_succ_iff, Bool.and_left_comm]
|
||||
· simp [replicate_succ, isPrefixOf_cons_cons, ih, Nat.succ_le_succ_iff, Bool.and_left_comm]
|
||||
|
||||
end isPrefixOf
|
||||
|
||||
@@ -169,18 +173,18 @@ theorem subset_replicate {n : Nat} {a : α} {l : List α} (h : n ≠ 0) : l ⊆
|
||||
|
||||
@[simp, grind ←] theorem Sublist.refl : ∀ l : List α, l <+ l
|
||||
| [] => .slnil
|
||||
| a :: l => (Sublist.refl l).cons₂ a
|
||||
| a :: l => (Sublist.refl l).cons_cons a
|
||||
|
||||
theorem Sublist.trans {l₁ l₂ l₃ : List α} (h₁ : l₁ <+ l₂) (h₂ : l₂ <+ l₃) : l₁ <+ l₃ := by
|
||||
induction h₂ generalizing l₁ with
|
||||
| slnil => exact h₁
|
||||
| cons _ _ IH => exact (IH h₁).cons _
|
||||
| @cons₂ l₂ _ a _ IH =>
|
||||
| @cons_cons l₂ _ a _ IH =>
|
||||
generalize e : a :: l₂ = l₂' at h₁
|
||||
match h₁ with
|
||||
| .slnil => apply nil_sublist
|
||||
| .cons a' h₁' => cases e; apply (IH h₁').cons
|
||||
| .cons₂ a' h₁' => cases e; apply (IH h₁').cons₂
|
||||
| .cons_cons a' h₁' => cases e; apply (IH h₁').cons_cons
|
||||
|
||||
instance : Trans (@Sublist α) Sublist Sublist := ⟨Sublist.trans⟩
|
||||
|
||||
@@ -193,23 +197,23 @@ theorem sublist_of_cons_sublist : a :: l₁ <+ l₂ → l₁ <+ l₂ :=
|
||||
|
||||
@[simp, grind =]
|
||||
theorem cons_sublist_cons : a :: l₁ <+ a :: l₂ ↔ l₁ <+ l₂ :=
|
||||
⟨fun | .cons _ s => sublist_of_cons_sublist s | .cons₂ _ s => s, .cons₂ _⟩
|
||||
⟨fun | .cons _ s => sublist_of_cons_sublist s | .cons_cons _ s => s, .cons_cons _⟩
|
||||
|
||||
theorem sublist_or_mem_of_sublist (h : l <+ l₁ ++ a :: l₂) : l <+ l₁ ++ l₂ ∨ a ∈ l := by
|
||||
induction l₁ generalizing l with
|
||||
| nil => match h with
|
||||
| .cons _ h => exact .inl h
|
||||
| .cons₂ _ h => exact .inr (.head ..)
|
||||
| .cons_cons _ h => exact .inr (.head ..)
|
||||
| cons b l₁ IH =>
|
||||
match h with
|
||||
| .cons _ h => exact (IH h).imp_left (Sublist.cons _)
|
||||
| .cons₂ _ h => exact (IH h).imp (Sublist.cons₂ _) (.tail _)
|
||||
| .cons_cons _ h => exact (IH h).imp (Sublist.cons_cons _) (.tail _)
|
||||
|
||||
@[grind →] theorem Sublist.subset : l₁ <+ l₂ → l₁ ⊆ l₂
|
||||
| .slnil, _, h => h
|
||||
| .cons _ s, _, h => .tail _ (s.subset h)
|
||||
| .cons₂ .., _, .head .. => .head ..
|
||||
| .cons₂ _ s, _, .tail _ h => .tail _ (s.subset h)
|
||||
| .cons_cons .., _, .head .. => .head ..
|
||||
| .cons_cons _ s, _, .tail _ h => .tail _ (s.subset h)
|
||||
|
||||
protected theorem Sublist.mem (hx : a ∈ l₁) (hl : l₁ <+ l₂) : a ∈ l₂ :=
|
||||
hl.subset hx
|
||||
@@ -245,7 +249,7 @@ theorem eq_nil_of_sublist_nil {l : List α} (s : l <+ []) : l = [] :=
|
||||
theorem Sublist.length_le : l₁ <+ l₂ → length l₁ ≤ length l₂
|
||||
| .slnil => Nat.le_refl 0
|
||||
| .cons _l s => le_succ_of_le (length_le s)
|
||||
| .cons₂ _ s => succ_le_succ (length_le s)
|
||||
| .cons_cons _ s => succ_le_succ (length_le s)
|
||||
|
||||
grind_pattern Sublist.length_le => l₁ <+ l₂, length l₁
|
||||
grind_pattern Sublist.length_le => l₁ <+ l₂, length l₂
|
||||
@@ -253,7 +257,7 @@ grind_pattern Sublist.length_le => l₁ <+ l₂, length l₂
|
||||
theorem Sublist.eq_of_length : l₁ <+ l₂ → length l₁ = length l₂ → l₁ = l₂
|
||||
| .slnil, _ => rfl
|
||||
| .cons a s, h => nomatch Nat.not_lt.2 s.length_le (h ▸ lt_succ_self _)
|
||||
| .cons₂ a s, h => by rw [s.eq_of_length (succ.inj h)]
|
||||
| .cons_cons a s, h => by rw [s.eq_of_length (succ.inj h)]
|
||||
|
||||
theorem Sublist.eq_of_length_le (s : l₁ <+ l₂) (h : length l₂ ≤ length l₁) : l₁ = l₂ :=
|
||||
s.eq_of_length <| Nat.le_antisymm s.length_le h
|
||||
@@ -275,7 +279,7 @@ grind_pattern tail_sublist => tail l <+ _
|
||||
protected theorem Sublist.tail : ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → tail l₁ <+ tail l₂
|
||||
| _, _, slnil => .slnil
|
||||
| _, _, Sublist.cons _ h => (tail_sublist _).trans h
|
||||
| _, _, Sublist.cons₂ _ h => h
|
||||
| _, _, Sublist.cons_cons _ h => h
|
||||
|
||||
@[grind →]
|
||||
theorem Sublist.of_cons_cons {l₁ l₂ : List α} {a b : α} (h : a :: l₁ <+ b :: l₂) : l₁ <+ l₂ :=
|
||||
@@ -287,8 +291,8 @@ protected theorem Sublist.map (f : α → β) {l₁ l₂} (s : l₁ <+ l₂) : m
|
||||
| slnil => simp
|
||||
| cons a s ih =>
|
||||
simpa using cons (f a) ih
|
||||
| cons₂ a s ih =>
|
||||
simpa using cons₂ (f a) ih
|
||||
| cons_cons a s ih =>
|
||||
simpa using cons_cons (f a) ih
|
||||
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₁
|
||||
grind_pattern Sublist.map => l₁ <+ l₂, map f l₂
|
||||
@@ -338,7 +342,7 @@ theorem sublist_filterMap_iff {l₁ : List β} {f : α → Option β} :
|
||||
cases h with
|
||||
| cons _ h =>
|
||||
exact ⟨l', h, rfl⟩
|
||||
| cons₂ _ h =>
|
||||
| cons_cons _ h =>
|
||||
rename_i l'
|
||||
exact ⟨l', h, by simp_all⟩
|
||||
· constructor
|
||||
@@ -347,10 +351,10 @@ theorem sublist_filterMap_iff {l₁ : List β} {f : α → Option β} :
|
||||
| cons _ h =>
|
||||
obtain ⟨l', s, rfl⟩ := ih.1 h
|
||||
exact ⟨l', Sublist.cons a s, rfl⟩
|
||||
| cons₂ _ h =>
|
||||
| cons_cons _ h =>
|
||||
rename_i l'
|
||||
obtain ⟨l', s, rfl⟩ := ih.1 h
|
||||
refine ⟨a :: l', Sublist.cons₂ a s, ?_⟩
|
||||
refine ⟨a :: l', Sublist.cons_cons a s, ?_⟩
|
||||
rwa [filterMap_cons_some]
|
||||
· rintro ⟨l', h, rfl⟩
|
||||
replace h := h.filterMap f
|
||||
@@ -369,7 +373,7 @@ theorem sublist_filter_iff {l₁ : List α} {p : α → Bool} :
|
||||
|
||||
theorem sublist_append_left : ∀ l₁ l₂ : List α, l₁ <+ l₁ ++ l₂
|
||||
| [], _ => nil_sublist _
|
||||
| _ :: l₁, l₂ => (sublist_append_left l₁ l₂).cons₂ _
|
||||
| _ :: l₁, l₂ => (sublist_append_left l₁ l₂).cons_cons _
|
||||
|
||||
grind_pattern sublist_append_left => Sublist, l₁ ++ l₂
|
||||
|
||||
@@ -382,7 +386,7 @@ grind_pattern sublist_append_right => Sublist, l₁ ++ l₂
|
||||
@[simp, grind =] theorem singleton_sublist {a : α} {l} : [a] <+ l ↔ a ∈ l := by
|
||||
refine ⟨fun h => h.subset (mem_singleton_self _), fun h => ?_⟩
|
||||
obtain ⟨_, _, rfl⟩ := append_of_mem h
|
||||
exact ((nil_sublist _).cons₂ _).trans (sublist_append_right ..)
|
||||
exact ((nil_sublist _).cons_cons _).trans (sublist_append_right ..)
|
||||
|
||||
@[simp] theorem sublist_append_of_sublist_left (s : l <+ l₁) : l <+ l₁ ++ l₂ :=
|
||||
s.trans <| sublist_append_left ..
|
||||
@@ -404,7 +408,7 @@ theorem Sublist.append_left : l₁ <+ l₂ → ∀ l, l ++ l₁ <+ l ++ l₂ :=
|
||||
theorem Sublist.append_right : l₁ <+ l₂ → ∀ l, l₁ ++ l <+ l₂ ++ l
|
||||
| .slnil, _ => Sublist.refl _
|
||||
| .cons _ h, _ => (h.append_right _).cons _
|
||||
| .cons₂ _ h, _ => (h.append_right _).cons₂ _
|
||||
| .cons_cons _ h, _ => (h.append_right _).cons_cons _
|
||||
|
||||
theorem Sublist.append (hl : l₁ <+ l₂) (hr : r₁ <+ r₂) : l₁ ++ r₁ <+ l₂ ++ r₂ :=
|
||||
(hl.append_right _).trans ((append_sublist_append_left _).2 hr)
|
||||
@@ -418,10 +422,10 @@ theorem sublist_cons_iff {a : α} {l l'} :
|
||||
· intro h
|
||||
cases h with
|
||||
| cons _ h => exact Or.inl h
|
||||
| cons₂ _ h => exact Or.inr ⟨_, rfl, h⟩
|
||||
| cons_cons _ h => exact Or.inr ⟨_, rfl, h⟩
|
||||
· rintro (h | ⟨r, rfl, h⟩)
|
||||
· exact h.cons _
|
||||
· exact h.cons₂ _
|
||||
· exact h.cons_cons _
|
||||
|
||||
@[grind =]
|
||||
theorem cons_sublist_iff {a : α} {l l'} :
|
||||
@@ -435,7 +439,7 @@ theorem cons_sublist_iff {a : α} {l l'} :
|
||||
| cons _ w =>
|
||||
obtain ⟨r₁, r₂, rfl, h₁, h₂⟩ := ih.1 w
|
||||
exact ⟨a' :: r₁, r₂, by simp, mem_cons_of_mem a' h₁, h₂⟩
|
||||
| cons₂ _ w =>
|
||||
| cons_cons _ w =>
|
||||
exact ⟨[a], l', by simp, mem_singleton_self _, w⟩
|
||||
· rintro ⟨r₁, r₂, w, h₁, h₂⟩
|
||||
rw [w, ← singleton_append]
|
||||
@@ -458,7 +462,7 @@ theorem sublist_append_iff {l : List α} :
|
||||
| cons _ w =>
|
||||
obtain ⟨l₁, l₂, rfl, w₁, w₂⟩ := ih.1 w
|
||||
exact ⟨l₁, l₂, rfl, Sublist.cons r w₁, w₂⟩
|
||||
| cons₂ _ w =>
|
||||
| cons_cons _ w =>
|
||||
rename_i l
|
||||
obtain ⟨l₁, l₂, rfl, w₁, w₂⟩ := ih.1 w
|
||||
refine ⟨r :: l₁, l₂, by simp, cons_sublist_cons.mpr w₁, w₂⟩
|
||||
@@ -466,9 +470,9 @@ theorem sublist_append_iff {l : List α} :
|
||||
cases w₁ with
|
||||
| cons _ w₁ =>
|
||||
exact Sublist.cons _ (Sublist.append w₁ w₂)
|
||||
| cons₂ _ w₁ =>
|
||||
| cons_cons _ w₁ =>
|
||||
rename_i l
|
||||
exact Sublist.cons₂ _ (Sublist.append w₁ w₂)
|
||||
exact Sublist.cons_cons _ (Sublist.append w₁ w₂)
|
||||
|
||||
theorem append_sublist_iff {l₁ l₂ : List α} :
|
||||
l₁ ++ l₂ <+ r ↔ ∃ r₁ r₂, r = r₁ ++ r₂ ∧ l₁ <+ r₁ ∧ l₂ <+ r₂ := by
|
||||
@@ -516,7 +520,7 @@ theorem Sublist.middle {l : List α} (h : l <+ l₁ ++ l₂) (a : α) : l <+ l
|
||||
theorem Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse
|
||||
| .slnil => Sublist.refl _
|
||||
| .cons _ h => by rw [reverse_cons]; exact sublist_append_of_sublist_left h.reverse
|
||||
| .cons₂ _ h => by rw [reverse_cons, reverse_cons]; exact h.reverse.append_right _
|
||||
| .cons_cons _ h => by rw [reverse_cons, reverse_cons]; exact h.reverse.append_right _
|
||||
|
||||
@[simp, grind =] theorem reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ :=
|
||||
⟨fun h => l₁.reverse_reverse ▸ l₂.reverse_reverse ▸ h.reverse, Sublist.reverse⟩
|
||||
@@ -558,7 +562,7 @@ theorem sublist_replicate_iff : l <+ replicate m a ↔ ∃ n, n ≤ m ∧ l = re
|
||||
obtain ⟨n, le, rfl⟩ := ih.1 (sublist_of_cons_sublist w)
|
||||
obtain rfl := (mem_replicate.1 (mem_of_cons_sublist w)).2
|
||||
exact ⟨n+1, Nat.add_le_add_right le 1, rfl⟩
|
||||
| cons₂ _ w =>
|
||||
| cons_cons _ w =>
|
||||
obtain ⟨n, le, rfl⟩ := ih.1 w
|
||||
refine ⟨n+1, Nat.add_le_add_right le 1, by simp [replicate_succ]⟩
|
||||
· rintro ⟨n, le, w⟩
|
||||
@@ -644,7 +648,7 @@ theorem flatten_sublist_iff {L : List (List α)} {l} :
|
||||
cases h_sub
|
||||
case cons h_sub =>
|
||||
exact isSublist_iff_sublist.mpr h_sub
|
||||
case cons₂ =>
|
||||
case cons_cons =>
|
||||
contradiction
|
||||
|
||||
instance [DecidableEq α] (l₁ l₂ : List α) : Decidable (l₁ <+ l₂) :=
|
||||
|
||||
@@ -393,7 +393,7 @@ theorem isPrefixOfAux_toArray_zero [BEq α] (l₁ l₂ : List α) (hle : l₁.le
|
||||
| [], _ => rw [dif_neg] <;> simp
|
||||
| _::_, [] => simp at hle
|
||||
| a::l₁, b::l₂ =>
|
||||
simp [isPrefixOf_cons₂, isPrefixOfAux_toArray_succ', isPrefixOfAux_toArray_zero]
|
||||
simp [isPrefixOf_cons_cons, isPrefixOfAux_toArray_succ', isPrefixOfAux_toArray_zero]
|
||||
|
||||
@[simp, grind =] theorem isPrefixOf_toArray [BEq α] (l₁ l₂ : List α) :
|
||||
l₁.toArray.isPrefixOf l₂.toArray = l₁.isPrefixOf l₂ := by
|
||||
@@ -407,7 +407,7 @@ theorem isPrefixOfAux_toArray_zero [BEq α] (l₁ l₂ : List α) (hle : l₁.le
|
||||
cases l₂ with
|
||||
| nil => simp
|
||||
| cons b l₂ =>
|
||||
simp only [isPrefixOf_cons₂, Bool.and_eq_false_imp]
|
||||
simp only [isPrefixOf_cons_cons, Bool.and_eq_false_imp]
|
||||
intro w
|
||||
rw [ih]
|
||||
simp_all
|
||||
@@ -589,7 +589,7 @@ theorem flatMap_toArray_cons {β} (f : α → Array β) (a : α) (as : List α)
|
||||
@[simp, grind =] theorem swap_toArray (l : List α) (i j : Nat) {hi hj}:
|
||||
l.toArray.swap i j hi hj = ((l.set i l[j]).set j l[i]).toArray := by
|
||||
apply ext'
|
||||
simp; rfl
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem eraseIdx_toArray (l : List α) (i : Nat) (h : i < l.toArray.size) :
|
||||
l.toArray.eraseIdx i h = (l.eraseIdx i).toArray := by
|
||||
@@ -644,8 +644,8 @@ private theorem insertIdx_loop_toArray (i : Nat) (l : List α) (j : Nat) (hj : j
|
||||
drop_append_of_le_length (by simp; omega)]
|
||||
simp only [append_assoc, cons_append, nil_append]
|
||||
cases i with
|
||||
| zero => simp; rfl
|
||||
| succ i => rw [take_set_of_le (by omega)]; rfl
|
||||
| zero => simp
|
||||
| succ i => rw [take_set_of_le (by omega)]
|
||||
· simp only [Nat.not_lt] at h'
|
||||
have : i = j := by omega
|
||||
subst this
|
||||
|
||||
@@ -400,7 +400,6 @@ theorem dfold_add
|
||||
induction m with
|
||||
| zero => simp; rfl
|
||||
| succ m ih =>
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
simp [dfold_congr (Nat.add_assoc n m 1).symm, ih]
|
||||
|
||||
@[simp] theorem dfoldRev_zero
|
||||
@@ -436,7 +435,6 @@ theorem dfoldRev_add
|
||||
induction m with
|
||||
| zero => simp; rfl
|
||||
| succ m ih =>
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
simp [← Nat.add_assoc, ih]
|
||||
|
||||
end Nat
|
||||
|
||||
@@ -444,7 +444,6 @@ instance : MonadAttach Option where
|
||||
CanReturn x a := x = some a
|
||||
attach x := x.attach
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
public instance : LawfulMonadAttach Option where
|
||||
map_attach {α} x := by simp [MonadAttach.attach]
|
||||
canReturn_map_imp {α P x a} := by
|
||||
@@ -456,7 +455,6 @@ end Option
|
||||
|
||||
namespace OptionT
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
public instance [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] :
|
||||
WeaklyLawfulMonadAttach (OptionT m) where
|
||||
map_attach {α} x := by
|
||||
|
||||
@@ -82,6 +82,15 @@ theorem get_inj {o1 o2 : Option α} {h1} {h2} :
|
||||
match o1, o2, h1, h2 with
|
||||
| some a, some b, _, _ => simp only [Option.get_some, Option.some.injEq]
|
||||
|
||||
theorem getD_inj {o₁ o₂ : Option α} (h₁ : o₁.isSome) (h₂ : o₂.isSome) {fallback} :
|
||||
o₁.getD fallback = o₂.getD fallback ↔ o₁ = o₂ := by
|
||||
match o₁, o₂, h₁, h₂ with
|
||||
| some a, some b, _, _ => simp only [Option.getD_some, Option.some.injEq]
|
||||
|
||||
theorem get!_inj [Inhabited α] {o₁ o₂ : Option α} (h₁ : o₁.isSome) (h₂ : o₂.isSome) :
|
||||
o₁.get! = o₂.get! ↔ o₁ = o₂ := by
|
||||
simpa [get!_eq_getD] using getD_inj h₁ h₂
|
||||
|
||||
theorem mem_unique {o : Option α} {a b : α} (ha : a ∈ o) (hb : b ∈ o) : a = b :=
|
||||
some.inj <| ha ▸ hb
|
||||
|
||||
|
||||
@@ -619,7 +619,7 @@ protected theorem compare_nil_right_eq_eq {α} [Ord α] {xs : List α} :
|
||||
end List
|
||||
|
||||
/-- The lexicographic order on pairs. -/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
compare := compareLex (compareOn (·.1)) (compareOn (·.2))
|
||||
|
||||
@@ -627,14 +627,14 @@ def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
Constructs an `BEq` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.eq`.
|
||||
-/
|
||||
@[expose, instance_reducible] def beqOfOrd [Ord α] : BEq α where
|
||||
@[expose, implicit_reducible] def beqOfOrd [Ord α] : BEq α where
|
||||
beq a b := (compare a b).isEq
|
||||
|
||||
/--
|
||||
Constructs an `LT` instance from an `Ord` instance that asserts that the result of `compare` is
|
||||
`Ordering.lt`.
|
||||
-/
|
||||
@[expose, instance_reducible] def ltOfOrd [Ord α] : LT α where
|
||||
@[expose, implicit_reducible] def ltOfOrd [Ord α] : LT α where
|
||||
lt a b := compare a b = Ordering.lt
|
||||
|
||||
@[inline]
|
||||
@@ -645,7 +645,7 @@ instance [Ord α] : DecidableRel (@LT.lt α ltOfOrd) := fun a b =>
|
||||
Constructs an `LE` instance from an `Ord` instance that asserts that the result of `compare`
|
||||
satisfies `Ordering.isLE`.
|
||||
-/
|
||||
@[expose, instance_reducible] def leOfOrd [Ord α] : LE α where
|
||||
@[expose, implicit_reducible] def leOfOrd [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
@[inline]
|
||||
@@ -677,7 +677,7 @@ Inverts the order of an `Ord` instance.
|
||||
The result is an `Ord α` instance that returns `Ordering.lt` when `ord` would return `Ordering.gt`
|
||||
and that returns `Ordering.gt` when `ord` would return `Ordering.lt`.
|
||||
-/
|
||||
@[expose, instance_reducible] protected def opposite (ord : Ord α) : Ord α where
|
||||
@[expose, implicit_reducible] protected def opposite (ord : Ord α) : Ord α where
|
||||
compare x y := ord.compare y x
|
||||
|
||||
/--
|
||||
@@ -688,7 +688,7 @@ In particular, `ord.on f` compares `x` and `y` by comparing `f x` and `f y` acco
|
||||
The function `compareOn` can be used to perform this comparison without constructing an intermediate
|
||||
`Ord` instance.
|
||||
-/
|
||||
@[expose, instance_reducible] protected def on (_ : Ord β) (f : α → β) : Ord α where
|
||||
@[expose, implicit_reducible] protected def on (_ : Ord β) (f : α → β) : Ord α where
|
||||
compare := compareOn f
|
||||
|
||||
/--
|
||||
@@ -707,7 +707,7 @@ The function `compareLex` can be used to perform this comparison without constru
|
||||
intermediate `Ord` instance. `Ordering.then` can be used to lexicographically combine the results of
|
||||
comparisons.
|
||||
-/
|
||||
@[expose, instance_reducible] protected def lex' (ord₁ ord₂ : Ord α) : Ord α where
|
||||
@[expose, implicit_reducible] protected def lex' (ord₁ ord₂ : Ord α) : Ord α where
|
||||
compare := compareLex ord₁.compare ord₂.compare
|
||||
|
||||
end Ord
|
||||
|
||||
@@ -23,7 +23,7 @@ preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMin α` instance.
|
||||
-/
|
||||
@[inline, instance_reducible]
|
||||
@[inline, implicit_reducible]
|
||||
public def _root_.Min.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Min α where
|
||||
min a b := if a ≤ b then a else b
|
||||
|
||||
@@ -33,7 +33,7 @@ preferring `a` over `b` when in doubt.
|
||||
|
||||
Has a `LawfulOrderLeftLeaningMax α` instance.
|
||||
-/
|
||||
@[inline, instance_reducible]
|
||||
@[inline, implicit_reducible]
|
||||
public def _root_.Max.leftLeaningOfLE (α : Type u) [LE α] [DecidableLE α] : Max α where
|
||||
max a b := if b ≤ a then a else b
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ Creates an `LE α` instance from an `Ord α` instance.
|
||||
`OrientedOrd α` must be satisfied so that the resulting `LE α` instance faithfully represents
|
||||
the `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose, implicit_reducible]
|
||||
public def _root_.LE.ofOrd (α : Type u) [Ord α] : LE α where
|
||||
le a b := (compare a b).isLE
|
||||
|
||||
@@ -39,7 +39,7 @@ Creates an `LT α` instance from an `Ord α` instance.
|
||||
`OrientedOrd α` must be satisfied so that the resulting `LT α` instance faithfully represents
|
||||
the `Ord α` instance.
|
||||
-/
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose, implicit_reducible]
|
||||
public def _root_.LT.ofOrd (α : Type u) [Ord α] :
|
||||
LT α where
|
||||
lt a b := compare a b = .lt
|
||||
@@ -104,7 +104,7 @@ public def _root_.DecidableLT.ofOrd (α : Type u) [LE α] [LT α] [Ord α] [Lawf
|
||||
|
||||
/--
|
||||
Creates a `BEq α` instance from an `Ord α` instance. -/
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose, implicit_reducible]
|
||||
public def _root_.BEq.ofOrd (α : Type u) [Ord α] :
|
||||
BEq α where
|
||||
beq a b := compare a b = .eq
|
||||
|
||||
@@ -124,6 +124,21 @@ public theorem min_apply [LE β] [DecidableLE β] [Min β] [LawfulOrderLeftLeani
|
||||
rw [min_eq_if, minOn]
|
||||
split <;> rfl
|
||||
|
||||
public theorem minOn_eq_if [LE β] [DecidableLE β] {f : α → β} {a b : α} :
|
||||
minOn f a b = if f a ≤ f b then a else b :=
|
||||
(rfl)
|
||||
|
||||
public theorem minOn_eq_min [Min α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMin α] [LE β]
|
||||
[DecidableLE β] {f : α → β} {a b : α} (hf : f a ≤ f b ↔ a ≤ b) :
|
||||
minOn f a b = min a b := by
|
||||
simp [minOn_eq_if, min_eq_if, hf]
|
||||
|
||||
public theorem min_apply_eq_min [LE α] [DecidableLE α] [Min α] [LawfulOrderLeftLeaningMin α]
|
||||
[Min β] [LE β] [DecidableLE β] [LawfulOrderLeftLeaningMin β]
|
||||
(f : α → β) {a b : α} (hf : f a ≤ f b ↔ a ≤ b) :
|
||||
min (f a) (f b) = f (min a b) := by
|
||||
rw [min_apply, minOn_eq_min hf]
|
||||
|
||||
/-! ## `maxOn` Lemmas -/
|
||||
|
||||
public theorem maxOn_eq_minOn [le : LE β] [DecidableLE β] {f : α → β} {x y : α} :
|
||||
@@ -195,3 +210,18 @@ public theorem max_apply [LE β] [DecidableLE β] [Max β] [LawfulOrderLeftLeani
|
||||
public theorem apply_maxOn [LE β] [DecidableLE β] [Max β] [LawfulOrderLeftLeaningMax β]
|
||||
{f : α → β} {x y : α} : f (maxOn f x y) = max (f x) (f y) :=
|
||||
max_apply.symm
|
||||
|
||||
public theorem maxOn_eq_if [LE β] [DecidableLE β] {f : α → β} {a b : α} :
|
||||
maxOn f a b = if f b ≤ f a then a else b := by
|
||||
simp only [maxOn_eq_minOn, minOn_eq_if, LE.le_opposite_iff]
|
||||
|
||||
public theorem maxOn_eq_max [Max α] [LE α] [DecidableLE α] [LawfulOrderLeftLeaningMax α] [LE β]
|
||||
[DecidableLE β] {f : α → β} {a b : α} (hf : f b ≤ f a ↔ b ≤ a) :
|
||||
maxOn f a b = max a b := by
|
||||
simp [maxOn_eq_if, max_eq_if, hf]
|
||||
|
||||
public theorem max_apply_eq_max [LE α] [DecidableLE α] [Max α] [LawfulOrderLeftLeaningMax α]
|
||||
[Max β] [LE β] [DecidableLE β] [LawfulOrderLeftLeaningMax β]
|
||||
(f : α → β) {a b : α} (hf : f b ≤ f a ↔ b ≤ a) :
|
||||
max (f a) (f b) = f (max a b) := by
|
||||
rw [max_apply, maxOn_eq_max hf]
|
||||
|
||||
@@ -52,7 +52,7 @@ def max' [LE α] [DecidableLE α] (a b : α) : α :=
|
||||
Without the `open scoped` command, Lean would not find the required {lit}`DecidableLE α`
|
||||
instance for the opposite order.
|
||||
-/
|
||||
@[instance_reducible] def LE.opposite (le : LE α) : LE α where
|
||||
@[implicit_reducible] def LE.opposite (le : LE α) : LE α where
|
||||
le a b := b ≤ a
|
||||
|
||||
theorem LE.opposite_def {le : LE α} :
|
||||
@@ -262,15 +262,18 @@ scoped instance (priority := low) instLawfulOrderOrdOpposite {il : LE α} {io :
|
||||
haveI := il.opposite
|
||||
haveI := io.opposite
|
||||
LawfulOrderOrd α :=
|
||||
@LawfulOrderOrd.mk α io.opposite il.opposite
|
||||
(by intros a b
|
||||
simp +instances only [LE.opposite, Ord.opposite]
|
||||
try simp [compare, LE.le]
|
||||
apply isLE_compare)
|
||||
(by intros a b
|
||||
simp +instances only [LE.opposite, Ord.opposite]
|
||||
try simp [compare, LE.le]
|
||||
apply isGE_compare)
|
||||
letI i := il.opposite
|
||||
letI j := io.opposite
|
||||
{ isLE_compare a b := by
|
||||
unfold LE.opposite Ord.opposite
|
||||
simp only [compare, LE.le]
|
||||
letI := il; letI := io
|
||||
apply isLE_compare
|
||||
isGE_compare a b := by
|
||||
unfold LE.opposite Ord.opposite
|
||||
simp only [compare, LE.le]
|
||||
letI := il; letI := io
|
||||
apply isGE_compare }
|
||||
|
||||
scoped instance (priority := low) instLawfulOrderLTOpposite {il : LE α} {it : LT α}
|
||||
[LawfulOrderLT α] :
|
||||
|
||||
@@ -8,6 +8,7 @@ module
|
||||
prelude
|
||||
public import Init.Data.Order.LemmasExtra -- shake: keep (instance inlined by `haveI`)
|
||||
public import Init.Data.Order.FactoriesExtra
|
||||
public import Init.Data.Order.Factories -- shake: keep (autoparam filling `Min.leftLeaningOfLE`)
|
||||
import Init.Data.Bool
|
||||
import Init.Data.Order.Lemmas
|
||||
|
||||
@@ -46,7 +47,7 @@ public instance instLawfulOrderBEqOfDecidableLE {α : Type u} [LE α] [Decidable
|
||||
beq_iff_le_and_ge := by simp [BEq.beq]
|
||||
|
||||
/-- If `LT` can be characterized in terms of a decidable `LE`, then `LT` is decidable either. -/
|
||||
@[expose]
|
||||
@[expose, instance_reducible]
|
||||
public def decidableLTOfLE {α : Type u} [LE α] {_ : LT α} [DecidableLE α] [LawfulOrderLT α] :
|
||||
DecidableLT α :=
|
||||
fun a b =>
|
||||
@@ -91,10 +92,11 @@ public structure Packages.PreorderOfLEArgs (α : Type u) where
|
||||
have := lt_iff
|
||||
DecidableLT α := by
|
||||
extract_lets
|
||||
haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..
|
||||
first
|
||||
| infer_instance
|
||||
| (haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..; infer_instance)
|
||||
| exact _root_.Std.FactoryInstances.decidableLTOfLE
|
||||
| (haveI := @_root_.Std.LawfulOrderLT.mk (lt_iff := by assumption) ..; exact _root_.Std.FactoryInstances.decidableLTOfLE)
|
||||
| fail "Failed to automatically derive that `LT` is decidable. \
|
||||
Please ensure that a `DecidableLT` instance can be synthesized or \
|
||||
manually provide the field `decidableLT`."
|
||||
@@ -169,7 +171,7 @@ automatically. If it fails, it is necessary to provide some of the fields manual
|
||||
* Other proof obligations, namely `le_refl` and `le_trans`, can be omitted if `Refl` and `Trans`
|
||||
instances can be synthesized.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
public def PreorderPackage.ofLE (α : Type u)
|
||||
(args : Packages.PreorderOfLEArgs α := by exact {}) : PreorderPackage α where
|
||||
toLE := args.le
|
||||
@@ -254,7 +256,7 @@ automatically. If it fails, it is necessary to provide some of the fields manual
|
||||
* Other proof obligations, namely `le_refl`, `le_trans` and `le_antisymm`, can be omitted if `Refl`,
|
||||
`Trans` and `Antisymm` instances can be synthesized.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
public def PartialOrderPackage.ofLE (α : Type u)
|
||||
(args : Packages.PartialOrderOfLEArgs α := by exact {}) : PartialOrderPackage α where
|
||||
toPreorderPackage := .ofLE α args.toPreorderOfLEArgs
|
||||
@@ -383,7 +385,7 @@ automatically. If it fails, it is necessary to provide some of the fields manual
|
||||
* Other proof obligations, namely `le_total` and `le_trans`, can be omitted if `Total` and `Trans`
|
||||
instances can be synthesized.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
public def LinearPreorderPackage.ofLE (α : Type u)
|
||||
(args : Packages.LinearPreorderOfLEArgs α := by exact {}) : LinearPreorderPackage α where
|
||||
toPreorderPackage := .ofLE α args.toPreorderOfLEArgs
|
||||
@@ -485,7 +487,7 @@ automatically. If it fails, it is necessary to provide some of the fields manual
|
||||
* Other proof obligations, namely `le_total`, `le_trans` and `le_antisymm`, can be omitted if
|
||||
`Total`, `Trans` and `Antisymm` instances can be synthesized.
|
||||
-/
|
||||
@[expose, instance_reducible]
|
||||
@[expose, implicit_reducible]
|
||||
public def LinearOrderPackage.ofLE (α : Type u)
|
||||
(args : Packages.LinearOrderOfLEArgs α := by exact {}) : LinearOrderPackage α where
|
||||
toLinearPreorderPackage := .ofLE α args.toLinearPreorderOfLEArgs
|
||||
@@ -645,7 +647,7 @@ automatically. If it fails, it is necessary to provide some of the fields manual
|
||||
* Other proof obligations, for example `transOrd`, can be omitted if a matching instance can be
|
||||
synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
@[expose, instance_reducible]
|
||||
public def LinearPreorderPackage.ofOrd (α : Type u)
|
||||
(args : Packages.LinearPreorderOfOrdArgs α := by exact {}) : LinearPreorderPackage α :=
|
||||
letI := args.ord
|
||||
@@ -791,10 +793,10 @@ automatically. If it fails, it is necessary to provide some of the fields manual
|
||||
* Other proof obligations, such as `transOrd`, can be omitted if matching instances can be
|
||||
synthesized.
|
||||
-/
|
||||
@[expose]
|
||||
@[expose, instance_reducible]
|
||||
public def LinearOrderPackage.ofOrd (α : Type u)
|
||||
(args : Packages.LinearOrderOfOrdArgs α := by exact {}) : LinearOrderPackage α :=
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
-- set_option backward.isDefEq.respectTransparency false in
|
||||
letI := LinearPreorderPackage.ofOrd α args.toLinearPreorderOfOrdArgs
|
||||
haveI : LawfulEqOrd α := ⟨args.eq_of_compare _ _⟩
|
||||
letI : Min α := args.min
|
||||
|
||||
@@ -6,16 +6,16 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
import Init.Data.BitVec.Bootstrap
|
||||
import Init.Data.BitVec.Lemmas
|
||||
import Init.Data.Int.DivMod.Lemmas
|
||||
import Init.Data.Int.Pow
|
||||
import Init.Data.Nat.Div.Lemmas
|
||||
import Init.Data.Nat.Lemmas
|
||||
import Init.Data.Nat.Mod
|
||||
import Init.Data.Option.Lemmas
|
||||
import Init.Data.Range.Polymorphic.BitVec
|
||||
import Init.Omega
|
||||
public import Init.Data.BitVec.Bootstrap
|
||||
public import Init.Data.BitVec.Lemmas
|
||||
public import Init.Data.Int.DivMod.Lemmas
|
||||
public import Init.Data.Int.Pow
|
||||
public import Init.Data.Nat.Div.Lemmas
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Nat.Mod
|
||||
public import Init.Data.Option.Lemmas
|
||||
public import Init.Data.Range.Polymorphic.BitVec
|
||||
public import Init.Omega
|
||||
|
||||
/-!
|
||||
# Ranges on signed bit vectors
|
||||
|
||||
@@ -486,7 +486,7 @@ public theorem Rxc.Iterator.toList_eq_toList_rxoIterator [LE α] [DecidableLE α
|
||||
· simp only [UpwardEnumerable.le_iff, UpwardEnumerable.lt_iff, *]
|
||||
split <;> rename_i h
|
||||
· rw [ihy]; rotate_left
|
||||
· simp [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
· simp [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLE, -- TODO
|
||||
Iterator.Monadic.step, Iter.toIterM, *]; rfl
|
||||
· simpa [UpwardEnumerable.lt_iff, UpwardEnumerable.le_iff, UpwardEnumerable.lt_succ_iff] using h
|
||||
· simpa [UpwardEnumerable.lt_iff, UpwardEnumerable.le_iff, UpwardEnumerable.lt_succ_iff] using h
|
||||
|
||||
@@ -102,7 +102,7 @@ theorem Iterator.Monadic.isPlausibleStep_iff [UpwardEnumerable α] [LE α] [Deci
|
||||
theorem Iterator.Monadic.step_eq_step [UpwardEnumerable α] [LE α] [DecidableLE α]
|
||||
{it : IterM (α := Rxc.Iterator α) Id α} :
|
||||
Std.Iterator.step it = pure (.deflate ⟨Iterator.Monadic.step it, isPlausibleStep_iff.mpr rfl⟩) := by
|
||||
simp [Std.Iterator.step]; rfl
|
||||
simp [Std.Iterator.step]
|
||||
|
||||
theorem Iterator.isPlausibleStep_iff [UpwardEnumerable α] [LE α] [DecidableLE α]
|
||||
{it : Iter (α := Rxc.Iterator α) α} {step} :
|
||||
@@ -184,7 +184,7 @@ theorem Iterator.Monadic.isPlausibleSuccessorOf_iff
|
||||
· rintro ⟨a, h, hP, h'⟩
|
||||
refine ⟨.yield it' a, rfl, ?_⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, step, h, hP, ↓reduceIte,
|
||||
IterStep.yield.injEq, and_true]
|
||||
IterStep.yield.injEq, and_true, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLE] -- TODO
|
||||
simp [h'.1, ← h'.2]
|
||||
|
||||
theorem Iterator.isPlausibleSuccessorOf_iff
|
||||
@@ -244,10 +244,10 @@ private def Iterator.instFinitenessRelation [UpwardEnumerable α] [LE α] [Decid
|
||||
intro bound
|
||||
constructor
|
||||
intro it' ⟨step, hs₁, hs₂⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step] at hs₂
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLE] at hs₂ -- TODO
|
||||
simp [hs₂, IterStep.successor] at hs₁
|
||||
simp only [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
Monadic.step, exists_eq_right] at hnone ⊢
|
||||
Monadic.step, exists_eq_right, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLE] at hnone ⊢ -- TODO
|
||||
match it with
|
||||
| ⟨⟨none, _⟩⟩ => apply hnone
|
||||
| ⟨⟨some init, bound⟩⟩ =>
|
||||
@@ -293,7 +293,7 @@ private def Iterator.instProductivenessRelation [UpwardEnumerable α] [LE α] [D
|
||||
subrelation {it it'} h := by
|
||||
exfalso
|
||||
simp only [IterM.IsPlausibleSkipSuccessorOf, IterM.IsPlausibleStep,
|
||||
Iterator.IsPlausibleStep, Monadic.step] at h
|
||||
Iterator.IsPlausibleStep, Monadic.step, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLE] at h
|
||||
split at h
|
||||
· cases h
|
||||
· split at h
|
||||
@@ -535,7 +535,6 @@ private theorem Iterator.instIteratorLoop.loop_eq_wf [UpwardEnumerable α] [LE
|
||||
· rw [WellFounded.fix_eq]
|
||||
simp_all
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
private theorem Iterator.instIteratorLoop.loopWf_eq [UpwardEnumerable α] [LE α] [DecidableLE α]
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
{n : Type u → Type w} [Monad n] [LawfulMonad n] (γ : Type u)
|
||||
@@ -581,13 +580,17 @@ private theorem Iterator.instIteratorLoop.loopWf_eq [UpwardEnumerable α] [LE α
|
||||
· simp
|
||||
· simp
|
||||
· rw [IterM.DefaultConsumers.forIn'_eq_match_step Pl wf]
|
||||
simp [IterM.step_eq, Monadic.step, instLawfulMonadLiftFunction.liftBind_pure, *]
|
||||
simp only [IterM.step_eq, instLawfulMonadLiftFunction.liftBind_pure, Shrink.inflate_deflate, *]
|
||||
-- Unfolding `Monadic.step` earlier would make some defeq checks fail on reducible transparency:
|
||||
-- `Iterator.IsPlausibleStep` is reducible and it reduces to `Monadic.step`, but `Monadic.step`
|
||||
-- is semireducible, and `simp` isn't able to unfold `Monadic.step` inside `Iterator.IsPlausibleStep`,
|
||||
-- since that one only appears in the type of a constant -- I think?
|
||||
simp [Monadic.step]
|
||||
· simp
|
||||
termination_by IteratorLoop.WithWF.mk ⟨⟨some next, upperBound⟩⟩ acc (hwf := wf)
|
||||
decreasing_by
|
||||
simp [IteratorLoop.rel, Monadic.isPlausibleStep_iff, Monadic.step, *]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
instance Iterator.instLawfulIteratorLoop [UpwardEnumerable α] [LE α] [DecidableLE α]
|
||||
[LawfulUpwardEnumerable α] [LawfulUpwardEnumerableLE α]
|
||||
{n : Type u → Type w} [Monad n] [LawfulMonad n] :
|
||||
@@ -598,7 +601,9 @@ instance Iterator.instLawfulIteratorLoop [UpwardEnumerable α] [LE α] [Decidabl
|
||||
IterM.DefaultConsumers.forIn'_eq_wf Pl wf]
|
||||
rw [IterM.DefaultConsumers.forIn'.wf]
|
||||
split; rotate_left
|
||||
· simp [IterM.step_eq, Monadic.step, Internal.LawfulMonadLiftBindFunction.liftBind_pure (liftBind := lift)]
|
||||
· simp only [IterM.step_eq,
|
||||
Internal.LawfulMonadLiftBindFunction.liftBind_pure (liftBind := lift), Shrink.inflate_deflate]
|
||||
simp [Monadic.step]
|
||||
rename_i next _
|
||||
rw [instIteratorLoop.loop_eq_wf Pl wf, instIteratorLoop.loopWf_eq (lift := lift)]
|
||||
simp only [IterM.step_mk, Monadic.step_eq_step, Monadic.step,
|
||||
@@ -680,7 +685,7 @@ theorem Iterator.Monadic.isPlausibleStep_iff [UpwardEnumerable α] [LT α] [Deci
|
||||
theorem Iterator.Monadic.step_eq_step [UpwardEnumerable α] [LT α] [DecidableLT α]
|
||||
{it : IterM (α := Rxo.Iterator α) Id α} :
|
||||
Std.Iterator.step it = pure (.deflate ⟨Iterator.Monadic.step it, isPlausibleStep_iff.mpr rfl⟩) := by
|
||||
simp [Std.Iterator.step]; rfl
|
||||
simp [Std.Iterator.step]
|
||||
|
||||
theorem Iterator.isPlausibleStep_iff [UpwardEnumerable α] [LT α] [DecidableLT α]
|
||||
{it : Iter (α := Rxo.Iterator α) α} {step} :
|
||||
@@ -762,7 +767,7 @@ theorem Iterator.Monadic.isPlausibleSuccessorOf_iff
|
||||
· rintro ⟨a, h, hP, h'⟩
|
||||
refine ⟨.yield it' a, rfl, ?_⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, step, h, hP, ↓reduceIte,
|
||||
IterStep.yield.injEq, and_true]
|
||||
IterStep.yield.injEq, and_true, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLT] -- TODO
|
||||
simp [h'.1, ← h'.2]
|
||||
|
||||
theorem Iterator.isPlausibleSuccessorOf_iff
|
||||
@@ -822,10 +827,10 @@ private def Iterator.instFinitenessRelation [UpwardEnumerable α] [LT α] [Decid
|
||||
intro bound
|
||||
constructor
|
||||
intro it' ⟨step, hs₁, hs₂⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step] at hs₂
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLT] at hs₂ -- TODO
|
||||
simp [hs₂, IterStep.successor] at hs₁
|
||||
simp only [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
Monadic.step, exists_eq_right] at hnone ⊢
|
||||
Monadic.step, exists_eq_right, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLT] at hnone ⊢ -- TODO
|
||||
match it with
|
||||
| ⟨⟨none, _⟩⟩ => apply hnone
|
||||
| ⟨⟨some init, bound⟩⟩ =>
|
||||
@@ -871,7 +876,7 @@ private def Iterator.instProductivenessRelation [UpwardEnumerable α] [LT α] [D
|
||||
subrelation {it it'} h := by
|
||||
exfalso
|
||||
simp only [IterM.IsPlausibleSkipSuccessorOf, IterM.IsPlausibleStep,
|
||||
Iterator.IsPlausibleStep, Monadic.step] at h
|
||||
Iterator.IsPlausibleStep, Monadic.step, instIteratorIteratorIdOfUpwardEnumerableOfDecidableLT] at h -- TODO
|
||||
split at h
|
||||
· cases h
|
||||
· split at h
|
||||
@@ -1244,7 +1249,7 @@ theorem Iterator.Monadic.isPlausibleStep_iff [UpwardEnumerable α]
|
||||
theorem Iterator.Monadic.step_eq_step [UpwardEnumerable α]
|
||||
{it : IterM (α := Rxi.Iterator α) Id α} :
|
||||
it.step = pure (.deflate ⟨Iterator.Monadic.step it, isPlausibleStep_iff.mpr rfl⟩) := by
|
||||
simp [IterM.step, Std.Iterator.step]; rfl
|
||||
simp [IterM.step, Std.Iterator.step]
|
||||
|
||||
theorem Iterator.isPlausibleStep_iff [UpwardEnumerable α]
|
||||
{it : Iter (α := Rxi.Iterator α) α} {step} :
|
||||
@@ -1310,7 +1315,7 @@ theorem Iterator.Monadic.isPlausibleSuccessorOf_iff
|
||||
· rintro ⟨a, h, h'⟩
|
||||
refine ⟨.yield it' a, rfl, ?_⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, step, h,
|
||||
IterStep.yield.injEq, and_true]
|
||||
IterStep.yield.injEq, and_true, instIteratorIteratorIdOfUpwardEnumerable] -- TODO
|
||||
simp [h']
|
||||
|
||||
theorem Iterator.isPlausibleSuccessorOf_iff
|
||||
@@ -1345,10 +1350,10 @@ private def Iterator.instFinitenessRelation [UpwardEnumerable α]
|
||||
⟨⟨none⟩⟩ := by
|
||||
constructor
|
||||
intro it' ⟨step, hs₁, hs₂⟩
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step] at hs₂
|
||||
simp only [IterM.IsPlausibleStep, Iterator.IsPlausibleStep, Monadic.step, instIteratorIteratorIdOfUpwardEnumerable] at hs₂ -- TODO
|
||||
simp [hs₂, IterStep.successor] at hs₁
|
||||
simp only [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
Monadic.step, exists_eq_right] at hnone ⊢
|
||||
Monadic.step, exists_eq_right, instIteratorIteratorIdOfUpwardEnumerable] at hnone ⊢ -- TODO
|
||||
match it with
|
||||
| ⟨⟨none⟩⟩ => apply hnone
|
||||
| ⟨⟨some init⟩⟩ =>
|
||||
@@ -1387,7 +1392,7 @@ private def Iterator.instProductivenessRelation [UpwardEnumerable α]
|
||||
subrelation {it it'} h := by
|
||||
exfalso
|
||||
simp only [IterM.IsPlausibleSkipSuccessorOf, IterM.IsPlausibleStep,
|
||||
Iterator.IsPlausibleStep, Monadic.step] at h
|
||||
Iterator.IsPlausibleStep, Monadic.step, instIteratorIteratorIdOfUpwardEnumerable] at h -- TODO
|
||||
split at h <;> cases h
|
||||
|
||||
@[no_expose]
|
||||
|
||||
@@ -10,7 +10,6 @@ prelude
|
||||
public import Init.Data.Range.Polymorphic.Instances
|
||||
public import Init.Data.SInt
|
||||
import all Init.Data.SInt.Basic
|
||||
|
||||
import all Init.Data.Range.Polymorphic.Internal.SignedBitVec
|
||||
import Init.ByCases
|
||||
import Init.Data.Int.LemmasAux
|
||||
@@ -246,9 +245,10 @@ instance : HasModel Int8 (BitVec 8) where
|
||||
decode x := .ofBitVec x
|
||||
encode_decode := by simp
|
||||
decode_encode := by simp
|
||||
le_iff_encode_le := by simp +instances [Int8.le_iff_toBitVec_sle, BitVec.Signed.instLE]
|
||||
lt_iff_encode_lt := by simp +instances [Int8.lt_iff_toBitVec_slt, BitVec.Signed.instLT]
|
||||
le_iff_encode_le := by simp [LE.le, Int8.le]
|
||||
lt_iff_encode_lt := by simp [LT.lt, Int8.lt]
|
||||
|
||||
set_option backward.whnf.reducibleClassField false in
|
||||
theorem instUpwardEnumerable_eq :
|
||||
instUpwardEnumerable = HasModel.instUpwardEnumerable := by
|
||||
apply UpwardEnumerable.ext
|
||||
@@ -259,6 +259,7 @@ theorem instUpwardEnumerable_eq :
|
||||
simp +instances [HasModel.succMany?_eq, instUpwardEnumerable, HasModel.encode, HasModel.decode,
|
||||
← toInt_toBitVec, toBitVec_maxValueSealed_eq_intMaxSealed, ofIntLE_eq_ofInt]
|
||||
|
||||
|
||||
instance : LawfulUpwardEnumerable Int8 := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
@@ -340,9 +341,10 @@ instance : HasModel Int16 (BitVec 16) where
|
||||
decode x := .ofBitVec x
|
||||
encode_decode := by simp
|
||||
decode_encode := by simp
|
||||
le_iff_encode_le := by simp +instances [Int16.le_iff_toBitVec_sle, BitVec.Signed.instLE]
|
||||
lt_iff_encode_lt := by simp +instances [Int16.lt_iff_toBitVec_slt, BitVec.Signed.instLT]
|
||||
le_iff_encode_le := by simp [LE.le, Int16.le]
|
||||
lt_iff_encode_lt := by simp [LT.lt, Int16.lt]
|
||||
|
||||
set_option backward.whnf.reducibleClassField false in
|
||||
theorem instUpwardEnumerable_eq :
|
||||
instUpwardEnumerable = HasModel.instUpwardEnumerable := by
|
||||
apply UpwardEnumerable.ext
|
||||
@@ -350,15 +352,16 @@ theorem instUpwardEnumerable_eq :
|
||||
apply HasModel.succ?_eq_of_technicalCondition
|
||||
simp [HasModel.encode, succ?, ← Int16.toBitVec_inj, toBitVec_minValueSealed_eq_intMinSealed]
|
||||
· ext
|
||||
simp +instances [HasModel.succMany?_eq, instUpwardEnumerable, HasModel.encode, HasModel.decode,
|
||||
simp only [HasModel.succMany?_eq]
|
||||
simp [UpwardEnumerable.succMany?, HasModel.encode, HasModel.decode,
|
||||
← toInt_toBitVec, toBitVec_maxValueSealed_eq_intMaxSealed, ofIntLE_eq_ofInt]
|
||||
|
||||
instance : LawfulUpwardEnumerable Int16 := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Int16 := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
public instance instRxcHasSize : Rxc.HasSize Int16 where
|
||||
@@ -370,7 +373,7 @@ theorem instRxcHasSize_eq :
|
||||
← toInt_toBitVec, HasModel.toNat_toInt_add_one_sub_toInt (Nat.zero_lt_succ _)]
|
||||
|
||||
public instance instRxcLawfulHasSize : Rxc.LawfulHasSize Int16 := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
infer_instance
|
||||
public instance : Rxc.IsAlwaysFinite Int16 := by exact inferInstance
|
||||
|
||||
@@ -387,7 +390,7 @@ theorem instRxiHasSize_eq :
|
||||
HasModel.encode, HasModel.toNat_two_pow_sub_one_sub_toInt (show 16 > 0 by omega)]
|
||||
|
||||
public instance instRxiLawfulHasSize : Rxi.LawfulHasSize Int16 := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
infer_instance
|
||||
public instance instRxiIsAlwaysFinite : Rxi.IsAlwaysFinite Int16 := by exact inferInstance
|
||||
|
||||
@@ -434,9 +437,10 @@ instance : HasModel Int32 (BitVec 32) where
|
||||
decode x := .ofBitVec x
|
||||
encode_decode := by simp
|
||||
decode_encode := by simp
|
||||
le_iff_encode_le := by simp +instances [Int32.le_iff_toBitVec_sle, BitVec.Signed.instLE]
|
||||
lt_iff_encode_lt := by simp +instances [Int32.lt_iff_toBitVec_slt, BitVec.Signed.instLT]
|
||||
le_iff_encode_le := by simp [LE.le, Int32.le]
|
||||
lt_iff_encode_lt := by simp [LT.lt, Int32.lt]
|
||||
|
||||
set_option backward.whnf.reducibleClassField false in
|
||||
theorem instUpwardEnumerable_eq :
|
||||
instUpwardEnumerable = HasModel.instUpwardEnumerable := by
|
||||
apply UpwardEnumerable.ext
|
||||
@@ -444,15 +448,16 @@ theorem instUpwardEnumerable_eq :
|
||||
apply HasModel.succ?_eq_of_technicalCondition
|
||||
simp [HasModel.encode, succ?, ← Int32.toBitVec_inj, toBitVec_minValueSealed_eq_intMinSealed]
|
||||
· ext
|
||||
simp +instances [HasModel.succMany?_eq, instUpwardEnumerable, HasModel.encode, HasModel.decode,
|
||||
simp only [HasModel.succMany?_eq]
|
||||
simp [UpwardEnumerable.succMany?, HasModel.encode, HasModel.decode,
|
||||
← toInt_toBitVec, toBitVec_maxValueSealed_eq_intMaxSealed, ofIntLE_eq_ofInt]
|
||||
|
||||
instance : LawfulUpwardEnumerable Int32 := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Int32 := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
public instance instRxcHasSize : Rxc.HasSize Int32 where
|
||||
@@ -464,7 +469,7 @@ theorem instRxcHasSize_eq :
|
||||
← toInt_toBitVec, HasModel.toNat_toInt_add_one_sub_toInt (Nat.zero_lt_succ _)]
|
||||
|
||||
public instance instRxcLawfulHasSize : Rxc.LawfulHasSize Int32 := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
infer_instance
|
||||
public instance : Rxc.IsAlwaysFinite Int32 := by exact inferInstance
|
||||
|
||||
@@ -481,7 +486,7 @@ theorem instRxiHasSize_eq :
|
||||
HasModel.encode, HasModel.toNat_two_pow_sub_one_sub_toInt (show 32 > 0 by omega)]
|
||||
|
||||
public instance instRxiLawfulHasSize : Rxi.LawfulHasSize Int32 := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
infer_instance
|
||||
public instance instRxiIsAlwaysFinite : Rxi.IsAlwaysFinite Int32 := by exact inferInstance
|
||||
|
||||
@@ -528,9 +533,10 @@ instance : HasModel Int64 (BitVec 64) where
|
||||
decode x := .ofBitVec x
|
||||
encode_decode := by simp
|
||||
decode_encode := by simp
|
||||
le_iff_encode_le := by simp +instances [Int64.le_iff_toBitVec_sle, BitVec.Signed.instLE]
|
||||
lt_iff_encode_lt := by simp +instances [Int64.lt_iff_toBitVec_slt, BitVec.Signed.instLT]
|
||||
le_iff_encode_le := by simp [LE.le, Int64.le]
|
||||
lt_iff_encode_lt := by simp [LT.lt, Int64.lt]
|
||||
|
||||
set_option backward.whnf.reducibleClassField false in
|
||||
theorem instUpwardEnumerable_eq :
|
||||
instUpwardEnumerable = HasModel.instUpwardEnumerable := by
|
||||
apply UpwardEnumerable.ext
|
||||
@@ -538,15 +544,16 @@ theorem instUpwardEnumerable_eq :
|
||||
apply HasModel.succ?_eq_of_technicalCondition
|
||||
simp [HasModel.encode, succ?, ← Int64.toBitVec_inj, toBitVec_minValueSealed_eq_intMinSealed]
|
||||
· ext
|
||||
simp +instances [HasModel.succMany?_eq, instUpwardEnumerable, HasModel.encode, HasModel.decode,
|
||||
simp only [HasModel.succMany?_eq]
|
||||
simp [UpwardEnumerable.succMany?, HasModel.encode, HasModel.decode,
|
||||
← toInt_toBitVec, toBitVec_maxValueSealed_eq_intMaxSealed, ofIntLE_eq_ofInt]
|
||||
|
||||
instance : LawfulUpwardEnumerable Int64 := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
instance : LawfulUpwardEnumerableLE Int64 := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
public instance instRxcHasSize : Rxc.HasSize Int64 where
|
||||
@@ -558,7 +565,7 @@ theorem instRxcHasSize_eq :
|
||||
← toInt_toBitVec, HasModel.toNat_toInt_add_one_sub_toInt (Nat.zero_lt_succ _)]
|
||||
|
||||
public instance instRxcLawfulHasSize : Rxc.LawfulHasSize Int64 := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
infer_instance
|
||||
public instance : Rxc.IsAlwaysFinite Int64 := by exact inferInstance
|
||||
|
||||
@@ -575,7 +582,7 @@ theorem instRxiHasSize_eq :
|
||||
HasModel.encode, HasModel.toNat_two_pow_sub_one_sub_toInt (show 64 > 0 by omega)]
|
||||
|
||||
public instance instRxiLawfulHasSize : Rxi.LawfulHasSize Int64 := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
infer_instance
|
||||
public instance instRxiIsAlwaysFinite : Rxi.IsAlwaysFinite Int64 := by exact inferInstance
|
||||
|
||||
@@ -627,9 +634,10 @@ instance : HasModel ISize (BitVec System.Platform.numBits) where
|
||||
decode x := .ofBitVec x
|
||||
encode_decode := by simp
|
||||
decode_encode := by simp
|
||||
le_iff_encode_le := by simp +instances [ISize.le_iff_toBitVec_sle, BitVec.Signed.instLE]
|
||||
lt_iff_encode_lt := by simp +instances [ISize.lt_iff_toBitVec_slt, BitVec.Signed.instLT]
|
||||
le_iff_encode_le := by simp [LE.le, ISize.le]
|
||||
lt_iff_encode_lt := by simp [LT.lt, ISize.lt]
|
||||
|
||||
set_option backward.whnf.reducibleClassField false in
|
||||
theorem instUpwardEnumerable_eq :
|
||||
instUpwardEnumerable = HasModel.instUpwardEnumerable := by
|
||||
apply UpwardEnumerable.ext
|
||||
@@ -637,15 +645,16 @@ theorem instUpwardEnumerable_eq :
|
||||
apply HasModel.succ?_eq_of_technicalCondition
|
||||
simp [HasModel.encode, succ?, ← ISize.toBitVec_inj, toBitVec_minValueSealed_eq_intMinSealed]
|
||||
· ext
|
||||
simp +instances [HasModel.succMany?_eq, instUpwardEnumerable, HasModel.encode, HasModel.decode,
|
||||
simp only [HasModel.succMany?_eq]
|
||||
simp [UpwardEnumerable.succMany?, HasModel.encode, HasModel.decode,
|
||||
← toInt_toBitVec, toBitVec_maxValueSealed_eq_intMaxSealed, ofIntLE_eq_ofInt]
|
||||
|
||||
instance : LawfulUpwardEnumerable ISize := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
instance : LawfulUpwardEnumerableLE ISize := by
|
||||
simp +instances only [instUpwardEnumerable_eq]
|
||||
rw [instUpwardEnumerable_eq]
|
||||
infer_instance
|
||||
|
||||
public instance instRxcHasSize : Rxc.HasSize ISize where
|
||||
@@ -657,7 +666,7 @@ theorem instRxcHasSize_eq :
|
||||
← toInt_toBitVec, HasModel.toNat_toInt_add_one_sub_toInt System.Platform.numBits_pos]
|
||||
|
||||
public instance instRxcLawfulHasSize : Rxc.LawfulHasSize ISize := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxcHasSize_eq]
|
||||
infer_instance
|
||||
public instance : Rxc.IsAlwaysFinite ISize := by exact inferInstance
|
||||
|
||||
@@ -674,7 +683,7 @@ theorem instRxiHasSize_eq :
|
||||
HasModel.encode, HasModel.toNat_two_pow_sub_one_sub_toInt System.Platform.numBits_pos]
|
||||
|
||||
public instance instRxiLawfulHasSize : Rxi.LawfulHasSize ISize := by
|
||||
simp +instances only [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
rw [instUpwardEnumerable_eq, instRxiHasSize_eq]
|
||||
infer_instance
|
||||
public instance instRxiIsAlwaysFinite : Rxi.IsAlwaysFinite ISize := by exact inferInstance
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ Examples:
|
||||
* `(if (5 : Int8) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int8) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int8_dec_lt", instance_reducible]
|
||||
@[extern "lean_int8_dec_lt", implicit_reducible]
|
||||
def Int8.decLt (a b : Int8) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -425,7 +425,7 @@ Examples:
|
||||
* `(if (15 : Int8) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int8) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int8_dec_le", instance_reducible]
|
||||
@[extern "lean_int8_dec_le", implicit_reducible]
|
||||
def Int8.decLe (a b : Int8) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -778,7 +778,7 @@ Examples:
|
||||
* `(if (5 : Int16) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int16) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int16_dec_lt", instance_reducible]
|
||||
@[extern "lean_int16_dec_lt", implicit_reducible]
|
||||
def Int16.decLt (a b : Int16) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -794,7 +794,7 @@ Examples:
|
||||
* `(if (15 : Int16) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int16) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int16_dec_le", instance_reducible]
|
||||
@[extern "lean_int16_dec_le", implicit_reducible]
|
||||
def Int16.decLe (a b : Int16) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -1163,7 +1163,7 @@ Examples:
|
||||
* `(if (5 : Int32) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int32) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int32_dec_lt", instance_reducible]
|
||||
@[extern "lean_int32_dec_lt", implicit_reducible]
|
||||
def Int32.decLt (a b : Int32) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -1179,7 +1179,7 @@ Examples:
|
||||
* `(if (15 : Int32) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int32) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int32_dec_le", instance_reducible]
|
||||
@[extern "lean_int32_dec_le", implicit_reducible]
|
||||
def Int32.decLe (a b : Int32) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -1568,7 +1568,7 @@ Examples:
|
||||
* `(if (5 : Int64) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : Int64) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_int64_dec_lt", instance_reducible]
|
||||
@[extern "lean_int64_dec_lt", implicit_reducible]
|
||||
def Int64.decLt (a b : Int64) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
/--
|
||||
@@ -1583,7 +1583,7 @@ Examples:
|
||||
* `(if (15 : Int64) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : Int64) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_int64_dec_le", instance_reducible]
|
||||
@[extern "lean_int64_dec_le", implicit_reducible]
|
||||
def Int64.decLe (a b : Int64) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
@@ -1958,7 +1958,7 @@ Examples:
|
||||
* `(if (5 : ISize) < 5 then "yes" else "no") = "no"`
|
||||
* `show ¬((7 : ISize) < 7) by decide`
|
||||
-/
|
||||
@[extern "lean_isize_dec_lt", instance_reducible]
|
||||
@[extern "lean_isize_dec_lt", implicit_reducible]
|
||||
def ISize.decLt (a b : ISize) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@@ -1974,7 +1974,7 @@ Examples:
|
||||
* `(if (15 : ISize) ≤ 5 then "yes" else "no") = "no"`
|
||||
* `show (7 : ISize) ≤ 7 by decide`
|
||||
-/
|
||||
@[extern "lean_isize_dec_le", instance_reducible]
|
||||
@[extern "lean_isize_dec_le", implicit_reducible]
|
||||
def ISize.decLe (a b : ISize) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ private def SubarrayIterator.instFinitelessRelation : FinitenessRelation (Subarr
|
||||
Rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.xs.stop - it.internalState.xs.start)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, step] at h
|
||||
simp [IterM.IsPlausibleSuccessorOf, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, step, instIteratorSubarrayIteratorId] at h -- TODO
|
||||
split at h
|
||||
· cases h
|
||||
simp only [InvImage, Subarray.stop, Subarray.start, WellFoundedRelation.rel, InvImage, sizeOf_nat]
|
||||
@@ -55,16 +55,13 @@ instance SubarrayIterator.instFinite : Finite (SubarrayIterator α) Id :=
|
||||
|
||||
instance [Monad m] : IteratorLoop (SubarrayIterator α) Id m := .defaultImplementation
|
||||
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose, implicit_reducible]
|
||||
def Subarray.instToIterator :=
|
||||
ToIterator.of (γ := Slice (Internal.SubarrayData α)) (β := α) (SubarrayIterator α) (⟨⟨·⟩⟩)
|
||||
attribute [instance] Subarray.instToIterator
|
||||
|
||||
universe v w
|
||||
|
||||
instance : SliceSize (Internal.SubarrayData α) where
|
||||
size s := s.internalRepresentation.stop - s.internalRepresentation.start
|
||||
|
||||
instance {α : Type u} {m : Type v → Type w} [Monad m] : ForIn m (Subarray α) α :=
|
||||
inferInstance
|
||||
|
||||
@@ -76,45 +73,6 @@ explicitly provide the wrapper function `Subarray.foldlM` for `Slice.foldlM`, pr
|
||||
specific docstring.
|
||||
-/
|
||||
|
||||
/--
|
||||
Folds a monadic operation from left to right over the elements in a subarray.
|
||||
An accumulator of type `β` is constructed by starting with `init` and monadically combining each
|
||||
element of the subarray with the current accumulator value in turn. The monad in question may permit
|
||||
early termination or repetition.
|
||||
Examples:
|
||||
```lean example
|
||||
#eval #["red", "green", "blue"].toSubarray.foldlM (init := "") fun acc x => do
|
||||
let l ← Option.guard (· ≠ 0) x.length
|
||||
return s!"{acc}({l}){x} "
|
||||
```
|
||||
```output
|
||||
some "(3)red (5)green (4)blue "
|
||||
```
|
||||
```lean example
|
||||
#eval #["red", "green", "blue"].toSubarray.foldlM (init := 0) fun acc x => do
|
||||
let l ← Option.guard (· ≠ 5) x.length
|
||||
return s!"{acc}({l}){x} "
|
||||
```
|
||||
```output
|
||||
none
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def Subarray.foldlM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : β → α → m β) (init : β) (as : Subarray α) : m β :=
|
||||
Slice.foldlM f (init := init) as
|
||||
|
||||
/--
|
||||
Folds an operation from left to right over the elements in a subarray.
|
||||
An accumulator of type `β` is constructed by starting with `init` and combining each
|
||||
element of the subarray with the current accumulator value in turn.
|
||||
Examples:
|
||||
* `#["red", "green", "blue"].toSubarray.foldl (· + ·.length) 0 = 12`
|
||||
* `#["red", "green", "blue"].toSubarray.popFront.foldl (· + ·.length) 0 = 9`
|
||||
-/
|
||||
@[inline]
|
||||
def Subarray.foldl {α : Type u} {β : Type v} (f : β → α → β) (init : β) (as : Subarray α) : β :=
|
||||
Slice.foldl f (init := init) as
|
||||
|
||||
/--
|
||||
The implementation of `ForIn.forIn` for `Subarray`, which allows it to be used with `for` loops in
|
||||
`do`-notation.
|
||||
@@ -126,16 +84,12 @@ def Subarray.forIn {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m]
|
||||
/--
|
||||
Allocates a new array that contains the contents of the subarray.
|
||||
-/
|
||||
@[coe]
|
||||
def Subarray.toArray (s : Subarray α) : Array α :=
|
||||
@[expose, coe]
|
||||
def Subarray.copy (s : Subarray α) : Array α :=
|
||||
Slice.toArray s
|
||||
|
||||
instance instCoeSubarrayArray : Coe (Subarray α) (Array α) :=
|
||||
⟨Subarray.toArray⟩
|
||||
|
||||
@[inherit_doc Subarray.toArray]
|
||||
def Subarray.copy (s : Subarray α) : Array α :=
|
||||
Slice.toArray s
|
||||
⟨Subarray.copy⟩
|
||||
|
||||
@[simp]
|
||||
theorem Subarray.copy_eq_toArray {s : Subarray α} :
|
||||
@@ -149,7 +103,7 @@ theorem Subarray.sliceToArray_eq_toArray {s : Subarray α} :
|
||||
|
||||
namespace Array
|
||||
|
||||
@[inherit_doc Subarray.toArray]
|
||||
@[inherit_doc Subarray.copy]
|
||||
def ofSubarray (s : Subarray α) : Array α :=
|
||||
Slice.toArray s
|
||||
|
||||
|
||||
@@ -36,11 +36,11 @@ theorem step_eq {it : Iter (α := SubarrayIterator α) α} :
|
||||
⟨.yield ⟨⟨it.1.xs.array, it.1.xs.start + 1, it.1.xs.stop, by omega, by assumption⟩⟩
|
||||
(it.1.xs.array[it.1.xs.start]'(by omega)),
|
||||
(by
|
||||
simp_all [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
simp_all [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, instIteratorSubarrayIteratorId, -- TODO
|
||||
SubarrayIterator.step, Iter.toIterM])⟩
|
||||
else
|
||||
⟨.done, (by
|
||||
simpa [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
simpa [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, instIteratorSubarrayIteratorId, -- TODO
|
||||
SubarrayIterator.step] using h)⟩ := by
|
||||
simp only [Iter.step, IterM.Step.toPure, Iter.toIter_toIterM, IterStep.mapIterator, IterM.step,
|
||||
Iterator.step, SubarrayIterator.step, Id.run_pure, Shrink.inflate_deflate]
|
||||
@@ -67,7 +67,6 @@ theorem val_step_eq {it : Iter (α := SubarrayIterator α) α} :
|
||||
simp only [step_eq]
|
||||
split <;> simp
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
theorem toList_eq {α : Type u} {it : Iter (α := SubarrayIterator α) α} :
|
||||
it.toList =
|
||||
(it.internalState.xs.array.toList.take it.internalState.xs.stop).drop it.internalState.xs.start := by
|
||||
@@ -84,7 +83,7 @@ theorem toList_eq {α : Type u} {it : Iter (α := SubarrayIterator α) α} :
|
||||
simp [it.internalState.xs.stop_le_array_size]
|
||||
exact h
|
||||
· simp [Subarray.array, Subarray.stop]
|
||||
· simp only [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep,
|
||||
· simp only [Iter.IsPlausibleStep, IterM.IsPlausibleStep, Iterator.IsPlausibleStep, instIteratorSubarrayIteratorId, -- TODO
|
||||
IterStep.mapIterator_yield, SubarrayIterator.step]
|
||||
rw [dif_pos]; rotate_left; exact h
|
||||
rfl
|
||||
@@ -106,13 +105,11 @@ theorem Internal.iter_eq {α : Type u} {s : Subarray α} :
|
||||
Internal.iter s = ⟨⟨s⟩⟩ :=
|
||||
rfl
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
theorem Internal.toList_iter {α : Type u} {s : Subarray α} :
|
||||
(Internal.iter s).toList =
|
||||
(s.array.toList.take s.stop).drop s.start := by
|
||||
simp [SubarrayIterator.toList_eq, Internal.iter_eq_toIteratorIter, ToIterator.iter_eq]
|
||||
|
||||
set_option backward.isDefEq.respectTransparency false in
|
||||
public instance : LawfulSliceSize (Internal.SubarrayData α) where
|
||||
lawful s := by
|
||||
simp [SliceSize.size, ToIterator.iter_eq,
|
||||
@@ -121,7 +118,7 @@ public instance : LawfulSliceSize (Internal.SubarrayData α) where
|
||||
|
||||
public theorem toArray_eq_sliceToArray {α : Type u} {s : Subarray α} :
|
||||
s.toArray = Slice.toArray s := by
|
||||
simp [Subarray.toArray]
|
||||
simp [Std.Slice.toArray]
|
||||
|
||||
@[simp]
|
||||
public theorem forIn_toList {α : Type u} {s : Subarray α}
|
||||
@@ -156,11 +153,11 @@ public theorem sliceFoldl_eq_foldl {α : Type u} {s : Subarray α} {f : β →
|
||||
public theorem foldlM_toList {m} [Monad m] {α : Type u} {s : Subarray α} {f}
|
||||
[LawfulMonad m] :
|
||||
s.toList.foldlM (init := init) f = s.foldlM (m := m) (init := init) f := by
|
||||
simp [Std.Slice.foldlM_toList, sliceFoldlM_eq_foldlM]
|
||||
simp [Std.Slice.foldlM_toList]
|
||||
|
||||
public theorem foldl_toList {α : Type u} {s : Subarray α} {f} :
|
||||
s.toList.foldl (init := init) f = s.foldl (init := init) f := by
|
||||
simp [Std.Slice.foldl_toList, sliceFoldl_eq_foldl]
|
||||
simp [Std.Slice.foldl_toList]
|
||||
|
||||
end Subarray
|
||||
|
||||
@@ -218,6 +215,7 @@ public theorem Array.stop_toSubarray {xs : Array α} {lo hi : Nat} :
|
||||
(xs.toSubarray lo hi).stop = min hi xs.size := by
|
||||
simp [toSubarray_eq_min, Subarray.stop]
|
||||
|
||||
set_option backward.whnf.reducibleClassField false in
|
||||
public theorem Subarray.toList_eq {xs : Subarray α} :
|
||||
xs.toList = (xs.array.extract xs.start xs.stop).toList := by
|
||||
let aslice := xs
|
||||
@@ -227,13 +225,13 @@ public theorem Subarray.toList_eq {xs : Subarray α} :
|
||||
change aslice.toList = _
|
||||
have : aslice.toList = lslice.toList := by
|
||||
rw [ListSlice.toList_eq]
|
||||
simp +instances only [aslice, lslice, Std.Slice.toList, Internal.toList_iter]
|
||||
simp only [aslice, lslice, Std.Slice.toList, Internal.toList_iter]
|
||||
apply List.ext_getElem
|
||||
· have : stop - start ≤ array.size - start := by omega
|
||||
simp [Subarray.start, Subarray.stop, *, Subarray.array]
|
||||
· intros
|
||||
simp [Subarray.array, Subarray.start, Subarray.stop]
|
||||
simp +instances [this, ListSlice.toList_eq, lslice]
|
||||
simp [this, ListSlice.toList_eq, lslice]
|
||||
|
||||
-- TODO: The current `List.extract_eq_drop_take` should be called `List.extract_eq_take_drop`
|
||||
private theorem Std.Internal.List.extract_eq_drop_take' {l : List α} {start stop : Nat} :
|
||||
@@ -251,21 +249,16 @@ public theorem Subarray.toList_eq_drop_take {xs : Subarray α} :
|
||||
xs.toList = (xs.array.toList.take xs.stop).drop xs.start := by
|
||||
rw [Subarray.toList_eq, Array.toList_extract, Std.Internal.List.extract_eq_drop_take']
|
||||
|
||||
@[grind =]
|
||||
public theorem Subarray.size_eq {xs : Subarray α} :
|
||||
xs.size = xs.stop - xs.start := by
|
||||
simp [Subarray.size]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem Subarray.size_drop {xs : Subarray α} :
|
||||
(xs.drop i).size = xs.size - i := by
|
||||
simp only [size, stop, drop, start]
|
||||
simp only [size_eq, stop, drop, start]
|
||||
omega
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem Subarray.size_take {xs : Subarray α} :
|
||||
(xs.take i).size = min i xs.size := by
|
||||
simp only [size, stop, take, start]
|
||||
simp only [size_eq, stop, take, start]
|
||||
omega
|
||||
|
||||
public theorem Subarray.sliceSize_eq_size {xs : Subarray α} :
|
||||
@@ -273,12 +266,12 @@ public theorem Subarray.sliceSize_eq_size {xs : Subarray α} :
|
||||
rfl
|
||||
|
||||
public theorem Subarray.getElem_eq_getElem_array {xs : Subarray α} {h : i < xs.size} :
|
||||
xs[i] = xs.array[xs.start + i]'(by simp only [size] at h; have := xs.stop_le_array_size; omega) := by
|
||||
xs[i] = xs.array[xs.start + i]'(by simp only [size_eq] at h; have := xs.stop_le_array_size; omega) := by
|
||||
rfl
|
||||
|
||||
public theorem Subarray.getElem_toList {xs : Subarray α} {h : i < xs.toList.length} :
|
||||
xs.toList[i]'h = xs[i]'(by simpa using h) := by
|
||||
simp [getElem_eq_getElem_array, toList_eq_drop_take]; rfl
|
||||
simp [getElem_eq_getElem_array, toList_eq_drop_take]
|
||||
|
||||
public theorem Subarray.getElem_eq_getElem_toList {xs : Subarray α} {h : i < xs.size} :
|
||||
xs[i]'h = xs.toList[i]'(by simpa using h) := by
|
||||
@@ -297,24 +290,24 @@ public theorem Subarray.toList_take {xs : Subarray α} :
|
||||
@[simp, grind =]
|
||||
public theorem Subarray.toArray_toList {xs : Subarray α} :
|
||||
xs.toList.toArray = xs.toArray := by
|
||||
simp [Std.Slice.toList, Subarray.toArray, Std.Slice.toArray]
|
||||
simp [Std.Slice.toList, Std.Slice.toArray, Std.Slice.toArray]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem Subarray.toList_toArray {xs : Subarray α} :
|
||||
xs.toArray.toList = xs.toList := by
|
||||
simp [Std.Slice.toList, Subarray.toArray, Std.Slice.toArray]
|
||||
simp [Std.Slice.toList, Std.Slice.toArray, Std.Slice.toArray]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem Subarray.length_toList {xs : Subarray α} :
|
||||
xs.toList.length = xs.size := by
|
||||
have : xs.start ≤ xs.stop := xs.internalRepresentation.start_le_stop
|
||||
have : xs.stop ≤ xs.array.size := xs.internalRepresentation.stop_le_array_size
|
||||
simp [Subarray.toList_eq, Subarray.size]; omega
|
||||
simp [Subarray.toList_eq, Subarray.size_eq]; omega
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem Subarray.size_toArray {xs : Subarray α} :
|
||||
xs.toArray.size = xs.size := by
|
||||
simp [← Subarray.toArray_toList, Subarray.size, Slice.size, SliceSize.size, start, stop]
|
||||
simp [← Subarray.toArray_toList, Subarray.size_eq, start, stop]
|
||||
|
||||
namespace Array
|
||||
|
||||
@@ -708,7 +701,7 @@ public theorem toList_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
Array.start_toSubarray, Array.stop_toSubarray, Array.toList_extract, List.take_drop,
|
||||
List.take_take]
|
||||
rw [Nat.add_sub_cancel' (by omega)]
|
||||
simp [Subarray.size, ← Array.length_toList, ← List.take_eq_take_min, Nat.add_comm xs.start]
|
||||
simp [Subarray.size_eq, ← Array.length_toList, ← List.take_eq_take_min, Nat.add_comm xs.start]
|
||||
|
||||
@[simp, grind =]
|
||||
public theorem toArray_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
@@ -718,7 +711,7 @@ public theorem toArray_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...hi].size = min hi xs.size - lo := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
public theorem mkSlice_rcc_eq_mkSlice_rco {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...=hi] = xs[lo...(hi + 1)] := by
|
||||
@@ -738,7 +731,7 @@ public theorem toArray_mkSlice_rcc {xs : Subarray α} {lo hi : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_rcc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo...=hi].size = min (hi + 1) xs.size - lo := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
public theorem mkSlice_rci_eq_mkSlice_rco {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo...*] = xs[lo...xs.size] := by
|
||||
@@ -758,7 +751,7 @@ public theorem toArray_mkSlice_rci {xs : Subarray α} {lo : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_rci {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo...*].size = xs.size - lo := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
public theorem mkSlice_roc_eq_mkSlice_roo {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[lo<...(hi + 1)] := by
|
||||
@@ -787,7 +780,7 @@ public theorem toArray_mkSlice_roo {xs : Subarray α} {lo hi : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_roo {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...hi].size = min hi xs.size - (lo + 1) := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
public theorem mkSlice_roc_eq_mkSlice_rcc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...=hi] = xs[(lo + 1)...=hi] := by
|
||||
@@ -806,7 +799,7 @@ public theorem toArray_mkSlice_roc {xs : Subarray α} {lo hi : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_roc {xs : Subarray α} {lo hi : Nat} :
|
||||
xs[lo<...=hi].size = min (hi + 1) xs.size - (lo + 1) := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
public theorem mkSlice_roi_eq_mkSlice_rci {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo<...*] = xs[(lo + 1)...*] := by
|
||||
@@ -830,7 +823,7 @@ public theorem toArray_mkSlice_roi {xs : Subarray α} {lo : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_roi {xs : Subarray α} {lo : Nat} :
|
||||
xs[lo<...*].size = xs.size - (lo + 1) := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
public theorem mkSlice_ric_eq_mkSlice_rio {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[*...(hi + 1)] := by
|
||||
@@ -859,7 +852,7 @@ public theorem toArray_mkSlice_rio {xs : Subarray α} {hi : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_rio {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...hi].size = min hi xs.size := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
public theorem mkSlice_ric_eq_mkSlice_rcc {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...=hi] = xs[0...=hi] := by
|
||||
@@ -880,7 +873,7 @@ public theorem toArray_mkSlice_ric {xs : Subarray α} {hi : Nat} :
|
||||
@[simp, grind =]
|
||||
public theorem size_mkSlice_ric {xs : Subarray α} {hi : Nat} :
|
||||
xs[*...=hi].size = min (hi + 1) xs.size := by
|
||||
simp [← Subarray.length_toList]
|
||||
simp [← length_toList, - length_toList_eq_size]
|
||||
|
||||
@[simp, grind =, grind =]
|
||||
public theorem mkSlice_rii {xs : Subarray α} :
|
||||
|
||||
@@ -21,7 +21,7 @@ open Std Std.Slice Std.PRange
|
||||
/--
|
||||
Internal representation of `ListSlice`, which is an abbreviation for `Slice ListSliceData`.
|
||||
-/
|
||||
public class Std.Slice.Internal.ListSliceData (α : Type u) where
|
||||
public structure Std.Slice.Internal.ListSliceData (α : Type u) where
|
||||
/-- The relevant suffix of the underlying list. -/
|
||||
list : List α
|
||||
/-- The maximum length of the slice, starting at the beginning of `list`. -/
|
||||
|
||||
@@ -22,7 +22,7 @@ open Std Slice PRange Iterators
|
||||
|
||||
variable {α : Type u}
|
||||
|
||||
@[inline, expose, instance_reducible]
|
||||
@[inline, expose, implicit_reducible]
|
||||
def ListSlice.instToIterator :=
|
||||
ToIterator.of (γ := Slice (Internal.ListSliceData α)) _ (fun s => match s.internalRepresentation.stop with
|
||||
| some n => s.internalRepresentation.list.iter.take n
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user