mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-14 08:04:07 +00:00
Compare commits
4 Commits
fix_grind_
...
refl_cmp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66400f8e77 | ||
|
|
e5315e0521 | ||
|
|
2472bdbaf2 | ||
|
|
732f55ec38 |
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -363,7 +363,7 @@ jobs:
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -407,7 +407,7 @@ jobs:
|
||||
echo -e "\n*Full commit log*\n" >> diff.md
|
||||
git log --oneline "$last_tag"..HEAD | sed 's/^/* /' >> diff.md
|
||||
- name: Release Nightly
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
|
||||
8
.github/workflows/pr-release.yml
vendored
8
.github/workflows/pr-release.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Download artifact from the previous workflow.
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v11 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
uses: dawidd6/action-download-artifact@v10 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
path: artifacts
|
||||
@@ -71,7 +71,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release (short format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
|
||||
- name: Release (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8
|
||||
uses: softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -151,7 +151,7 @@ jobs:
|
||||
|
||||
- name: 'Setup jq'
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: dcarbone/install-jq-action@v3.2.0
|
||||
uses: dcarbone/install-jq-action@v3.1.1
|
||||
|
||||
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD for Mathlib/Batteries
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -31,4 +31,3 @@ fwOut.txt
|
||||
wdErr.txt
|
||||
wdIn.txt
|
||||
wdOut.txt
|
||||
downstream_releases/
|
||||
|
||||
@@ -16,7 +16,7 @@ foreach(var ${vars})
|
||||
list(APPEND STAGE1_ARGS "-D${CMAKE_MATCH_1}=${${var}}")
|
||||
elseif("${currentHelpString}" MATCHES "No help, variable specified on the command line." OR "${currentHelpString}" STREQUAL "")
|
||||
list(APPEND CL_ARGS "-D${var}=${${var}}")
|
||||
if("${var}" MATCHES "USE_GMP|CHECK_OLEAN_VERSION|LEAN_VERSION_.*|LEAN_SPECIAL_VERSION_DESC")
|
||||
if("${var}" MATCHES "USE_GMP|CHECK_OLEAN_VERSION")
|
||||
# must forward options that generate incompatible .olean format
|
||||
list(APPEND STAGE0_ARGS "-D${var}=${${var}}")
|
||||
elseif("${var}" MATCHES "LLVM*|PKG_CONFIG|USE_LAKE|USE_MIMALLOC")
|
||||
|
||||
@@ -68,7 +68,7 @@ The memory order of the fields is derived from the types and order of the fields
|
||||
* Fields of type `USize`
|
||||
* Other scalar fields, in decreasing order by size
|
||||
|
||||
Within each group the fields are ordered in declaration order. Trivial wrapper types count as their underlying wrapped type for this purpose.
|
||||
Within each group the fields are ordered in declaration order. **Warning**: Trivial wrapper types still count toward a field being treated as non-scalar for this purpose.
|
||||
|
||||
* To access fields of the first kind, use `lean_ctor_get(val, i)` to get the `i`th non-scalar field.
|
||||
* To access `USize` fields, use `lean_ctor_get_usize(val, n+i)` to get the `i`th usize field and `n` is the total number of fields of the first kind.
|
||||
@@ -80,32 +80,32 @@ structure S where
|
||||
ptr_1 : Array Nat
|
||||
usize_1 : USize
|
||||
sc64_1 : UInt64
|
||||
sc64_2 : { x : UInt64 // x > 0 } -- wrappers of scalars count as scalars
|
||||
sc64_3 : Float -- `Float` is 64 bit
|
||||
ptr_2 : { x : UInt64 // x > 0 } -- wrappers don't count as scalars
|
||||
sc64_2 : Float -- `Float` is 64 bit
|
||||
sc8_1 : Bool
|
||||
sc16_1 : UInt16
|
||||
sc8_2 : UInt8
|
||||
sc64_4 : UInt64
|
||||
sc64_3 : UInt64
|
||||
usize_2 : USize
|
||||
sc32_1 : Char -- trivial wrapper around `UInt32`
|
||||
sc32_2 : UInt32
|
||||
ptr_3 : Char -- trivial wrapper around `UInt32`
|
||||
sc32_1 : UInt32
|
||||
sc16_2 : UInt16
|
||||
```
|
||||
would get re-sorted into the following memory order:
|
||||
|
||||
* `S.ptr_1` - `lean_ctor_get(val, 0)`
|
||||
* `S.usize_1` - `lean_ctor_get_usize(val, 1)`
|
||||
* `S.usize_2` - `lean_ctor_get_usize(val, 2)`
|
||||
* `S.sc64_1` - `lean_ctor_get_uint64(val, sizeof(void*)*3)`
|
||||
* `S.sc64_2` - `lean_ctor_get_uint64(val, sizeof(void*)*3 + 8)`
|
||||
* `S.sc64_3` - `lean_ctor_get_float(val, sizeof(void*)*3 + 16)`
|
||||
* `S.sc64_4` - `lean_ctor_get_uint64(val, sizeof(void*)*3 + 24)`
|
||||
* `S.sc32_1` - `lean_ctor_get_uint32(val, sizeof(void*)*3 + 32)`
|
||||
* `S.sc32_2` - `lean_ctor_get_uint32(val, sizeof(void*)*3 + 36)`
|
||||
* `S.sc16_1` - `lean_ctor_get_uint16(val, sizeof(void*)*3 + 40)`
|
||||
* `S.sc16_2` - `lean_ctor_get_uint16(val, sizeof(void*)*3 + 42)`
|
||||
* `S.sc8_1` - `lean_ctor_get_uint8(val, sizeof(void*)*3 + 44)`
|
||||
* `S.sc8_2` - `lean_ctor_get_uint8(val, sizeof(void*)*3 + 45)`
|
||||
* `S.ptr_2` - `lean_ctor_get(val, 1)`
|
||||
* `S.ptr_3` - `lean_ctor_get(val, 2)`
|
||||
* `S.usize_1` - `lean_ctor_get_usize(val, 3)`
|
||||
* `S.usize_2` - `lean_ctor_get_usize(val, 4)`
|
||||
* `S.sc64_1` - `lean_ctor_get_uint64(val, sizeof(void*)*5)`
|
||||
* `S.sc64_2` - `lean_ctor_get_float(val, sizeof(void*)*5 + 8)`
|
||||
* `S.sc64_3` - `lean_ctor_get_uint64(val, sizeof(void*)*5 + 16)`
|
||||
* `S.sc32_1` - `lean_ctor_get_uint32(val, sizeof(void*)*5 + 24)`
|
||||
* `S.sc16_1` - `lean_ctor_get_uint16(val, sizeof(void*)*5 + 28)`
|
||||
* `S.sc16_2` - `lean_ctor_get_uint16(val, sizeof(void*)*5 + 30)`
|
||||
* `S.sc8_1` - `lean_ctor_get_uint8(val, sizeof(void*)*5 + 32)`
|
||||
* `S.sc8_2` - `lean_ctor_get_uint8(val, sizeof(void*)*5 + 33)`
|
||||
|
||||
### Borrowing
|
||||
|
||||
|
||||
@@ -3,32 +3,6 @@ import sys
|
||||
import subprocess
|
||||
import requests
|
||||
|
||||
def check_gh_auth():
|
||||
"""Check if GitHub CLI is properly authenticated."""
|
||||
try:
|
||||
result = subprocess.run(["gh", "auth", "status"], capture_output=True, text=True)
|
||||
if result.returncode != 0:
|
||||
return False, result.stderr
|
||||
return True, None
|
||||
except FileNotFoundError:
|
||||
return False, "GitHub CLI (gh) is not installed. Please install it first."
|
||||
except Exception as e:
|
||||
return False, f"Error checking authentication: {e}"
|
||||
|
||||
def handle_gh_error(error_output):
|
||||
"""Handle GitHub CLI errors and provide helpful messages."""
|
||||
if "Not Found (HTTP 404)" in error_output:
|
||||
return "Repository not found or access denied. Please check:\n" \
|
||||
"1. The repository name is correct\n" \
|
||||
"2. You have access to the repository\n" \
|
||||
"3. Your GitHub CLI authentication is valid"
|
||||
elif "Bad credentials" in error_output or "invalid" in error_output.lower():
|
||||
return "Authentication failed. Please run 'gh auth login' to re-authenticate."
|
||||
elif "rate limit" in error_output.lower():
|
||||
return "GitHub API rate limit exceeded. Please try again later."
|
||||
else:
|
||||
return f"GitHub API error: {error_output}"
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 4:
|
||||
print("Usage: ./push_repo_release_tag.py <repo> <branch> <version_tag>")
|
||||
@@ -40,13 +14,6 @@ def main():
|
||||
print(f"Error: Branch '{branch}' is not 'master' or 'main'.")
|
||||
sys.exit(1)
|
||||
|
||||
# Check GitHub CLI authentication first
|
||||
auth_ok, auth_error = check_gh_auth()
|
||||
if not auth_ok:
|
||||
print(f"Authentication error: {auth_error}")
|
||||
print("\nTo fix this, run: gh auth login")
|
||||
sys.exit(1)
|
||||
|
||||
# Get the `lean-toolchain` file content
|
||||
lean_toolchain_url = f"https://raw.githubusercontent.com/{repo}/{branch}/lean-toolchain"
|
||||
try:
|
||||
@@ -76,23 +43,12 @@ def main():
|
||||
for tag in existing_tags:
|
||||
print(tag.replace("refs/tags/", ""))
|
||||
sys.exit(1)
|
||||
elif list_tags_output.returncode != 0:
|
||||
# Handle API errors when listing tags
|
||||
error_msg = handle_gh_error(list_tags_output.stderr)
|
||||
print(f"Error checking existing tags: {error_msg}")
|
||||
sys.exit(1)
|
||||
|
||||
# Get the SHA of the branch
|
||||
get_sha_cmd = [
|
||||
"gh", "api", f"repos/{repo}/git/ref/heads/{branch}", "--jq", ".object.sha"
|
||||
]
|
||||
sha_result = subprocess.run(get_sha_cmd, capture_output=True, text=True)
|
||||
|
||||
if sha_result.returncode != 0:
|
||||
error_msg = handle_gh_error(sha_result.stderr)
|
||||
print(f"Error getting branch SHA: {error_msg}")
|
||||
sys.exit(1)
|
||||
|
||||
sha_result = subprocess.run(get_sha_cmd, capture_output=True, text=True, check=True)
|
||||
sha = sha_result.stdout.strip()
|
||||
|
||||
# Create the tag
|
||||
@@ -102,20 +58,11 @@ def main():
|
||||
"-F", f"ref=refs/tags/{version_tag}",
|
||||
"-F", f"sha={sha}"
|
||||
]
|
||||
create_result = subprocess.run(create_tag_cmd, capture_output=True, text=True)
|
||||
|
||||
if create_result.returncode != 0:
|
||||
error_msg = handle_gh_error(create_result.stderr)
|
||||
print(f"Error creating tag: {error_msg}")
|
||||
sys.exit(1)
|
||||
subprocess.run(create_tag_cmd, capture_output=True, text=True, check=True)
|
||||
|
||||
print(f"Successfully created and pushed tag '{version_tag}' to {repo}.")
|
||||
except subprocess.CalledProcessError as e:
|
||||
error_msg = handle_gh_error(e.stderr.strip() if e.stderr else str(e))
|
||||
print(f"Error while creating/pushing tag: {error_msg}")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"Unexpected error: {e}")
|
||||
print(f"Error while creating/pushing tag: {e.stderr.strip() if e.stderr else e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -231,43 +231,6 @@ def get_next_version(version):
|
||||
# Next version is always .0
|
||||
return f"v{major}.{minor + 1}.0"
|
||||
|
||||
def get_latest_nightly_tag(github_token):
|
||||
"""Get the most recent nightly tag from leanprover/lean4-nightly."""
|
||||
api_url = "https://api.github.com/repos/leanprover/lean4-nightly/tags"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
response = requests.get(api_url, headers=headers)
|
||||
if response.status_code != 200:
|
||||
return None
|
||||
tags = response.json()
|
||||
if not tags:
|
||||
return None
|
||||
# Return the most recent tag name
|
||||
return tags[0]['name']
|
||||
|
||||
def update_lean_toolchain_in_branch(org_repo, branch, toolchain_content, github_token):
|
||||
"""Update the lean-toolchain file in a specific branch."""
|
||||
api_url = f"https://api.github.com/repos/{org_repo}/contents/lean-toolchain"
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
|
||||
# First get the current file to get its SHA
|
||||
response = requests.get(f"{api_url}?ref={branch}", headers=headers)
|
||||
if response.status_code != 200:
|
||||
return False
|
||||
|
||||
current_file = response.json()
|
||||
file_sha = current_file['sha']
|
||||
|
||||
# Update the file
|
||||
update_data = {
|
||||
"message": f"chore: update lean-toolchain to {toolchain_content}",
|
||||
"content": base64.b64encode(toolchain_content.encode('utf-8')).decode('utf-8'),
|
||||
"sha": file_sha,
|
||||
"branch": branch
|
||||
}
|
||||
|
||||
response = requests.put(api_url, json=update_data, headers=headers)
|
||||
return response.status_code in [200, 201]
|
||||
|
||||
def check_bump_branch_toolchain(url, bump_branch, github_token):
|
||||
"""Check if the lean-toolchain file in bump branch starts with either 'leanprover/lean4:nightly-' or the next version."""
|
||||
content = get_branch_content(url, bump_branch, "lean-toolchain", github_token)
|
||||
@@ -299,61 +262,6 @@ def pr_exists_with_title(repo_url, title, github_token):
|
||||
return pr['number'], pr['html_url']
|
||||
return None
|
||||
|
||||
def check_proofwidgets4_release(repo_url, target_toolchain, github_token):
|
||||
"""Check if ProofWidgets4 has a release tag that uses the target toolchain."""
|
||||
api_base = repo_url.replace("https://github.com/", "https://api.github.com/repos/")
|
||||
headers = {'Authorization': f'token {github_token}'} if github_token else {}
|
||||
|
||||
# Get all tags matching v0.0.* pattern
|
||||
response = requests.get(f"{api_base}/git/matching-refs/tags/v0.0.", headers=headers)
|
||||
if response.status_code != 200:
|
||||
print(f" ❌ Could not fetch ProofWidgets4 tags")
|
||||
return False
|
||||
|
||||
tags = response.json()
|
||||
if not tags:
|
||||
print(f" ❌ No v0.0.* tags found for ProofWidgets4")
|
||||
return False
|
||||
|
||||
# Extract tag names and sort by version number (descending)
|
||||
tag_names = []
|
||||
for tag in tags:
|
||||
ref = tag['ref']
|
||||
if ref.startswith('refs/tags/v0.0.'):
|
||||
tag_name = ref.replace('refs/tags/', '')
|
||||
try:
|
||||
# Extract the number after v0.0.
|
||||
version_num = int(tag_name.split('.')[-1])
|
||||
tag_names.append((version_num, tag_name))
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
|
||||
if not tag_names:
|
||||
print(f" ❌ No valid v0.0.* tags found for ProofWidgets4")
|
||||
return False
|
||||
|
||||
# Sort by version number (descending) and take the most recent 10
|
||||
tag_names.sort(reverse=True)
|
||||
recent_tags = tag_names[:10]
|
||||
|
||||
# Check each recent tag to see if it uses the target toolchain
|
||||
for version_num, tag_name in recent_tags:
|
||||
toolchain_content = get_branch_content(repo_url, tag_name, "lean-toolchain", github_token)
|
||||
if toolchain_content is None:
|
||||
continue
|
||||
|
||||
if is_version_gte(toolchain_content.strip(), target_toolchain):
|
||||
print(f" ✅ Found release {tag_name} using compatible toolchain (>= {target_toolchain})")
|
||||
return True
|
||||
|
||||
# If we get here, no recent release uses the target toolchain
|
||||
# Find the highest version number to suggest the next one
|
||||
highest_version = max(version_num for version_num, _ in recent_tags)
|
||||
next_version = highest_version + 1
|
||||
print(f" ❌ No recent ProofWidgets4 release uses toolchain >= {target_toolchain}")
|
||||
print(f" You will need to create and push a tag v0.0.{next_version}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Check release status of Lean4 repositories")
|
||||
parser.add_argument("toolchain", help="The toolchain version to check (e.g., v4.6.0)")
|
||||
@@ -478,12 +386,6 @@ def main():
|
||||
continue
|
||||
print(f" ✅ On compatible toolchain (>= {toolchain})")
|
||||
|
||||
# Special handling for ProofWidgets4
|
||||
if name == "ProofWidgets4":
|
||||
if not check_proofwidgets4_release(url, toolchain, github_token):
|
||||
repo_status[name] = False
|
||||
continue
|
||||
|
||||
if check_tag:
|
||||
tag_exists_initially = tag_exists(url, toolchain, github_token)
|
||||
if not tag_exists_initially:
|
||||
@@ -492,7 +394,7 @@ def main():
|
||||
repo_status[name] = False
|
||||
continue
|
||||
else:
|
||||
print(f" ⮕ Tag {toolchain} does not exist. Running `script/push_repo_release_tag.py {org_repo} {branch} {toolchain}`...")
|
||||
print(f" … Tag {toolchain} does not exist. Running `script/push_repo_release_tag.py {org_repo} {branch} {toolchain}`...")
|
||||
|
||||
# Run the script to create the tag
|
||||
subprocess.run(["script/push_repo_release_tag.py", org_repo, branch, toolchain])
|
||||
@@ -515,7 +417,7 @@ def main():
|
||||
repo_status[name] = False
|
||||
continue
|
||||
else:
|
||||
print(f" ⮕ Tag {toolchain} is not merged into stable. Running `script/merge_remote.py {org_repo} stable {toolchain}`...")
|
||||
print(f" … Tag {toolchain} is not merged into stable. Running `script/merge_remote.py {org_repo} stable {toolchain}`...")
|
||||
|
||||
# Run the script to merge the tag
|
||||
subprocess.run(["script/merge_remote.py", org_repo, "stable", toolchain])
|
||||
@@ -532,49 +434,19 @@ def main():
|
||||
if check_bump:
|
||||
next_version = get_next_version(toolchain)
|
||||
bump_branch = f"bump/{next_version}"
|
||||
|
||||
# For mathlib4, use the nightly-testing fork for bump branches
|
||||
bump_org_repo = org_repo
|
||||
bump_url = url
|
||||
if name == "mathlib4":
|
||||
bump_org_repo = "leanprover-community/mathlib4-nightly-testing"
|
||||
bump_url = "https://github.com/leanprover-community/mathlib4-nightly-testing"
|
||||
|
||||
branch_created = False
|
||||
if not branch_exists(bump_url, bump_branch, github_token):
|
||||
if not branch_exists(url, bump_branch, github_token):
|
||||
if args.dry_run:
|
||||
latest_nightly = get_latest_nightly_tag(github_token)
|
||||
nightly_note = f" (will set lean-toolchain to {latest_nightly})" if name in ["batteries", "mathlib4"] and latest_nightly else ""
|
||||
print(f" ❌ Bump branch {bump_branch} does not exist. Run `gh api -X POST /repos/{bump_org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)` to create it{nightly_note}.")
|
||||
print(f" ❌ Bump branch {bump_branch} does not exist. Run `gh api -X POST /repos/{org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)` to create it.")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
print(f" ⮕ Bump branch {bump_branch} does not exist. Creating it...")
|
||||
result = run_command(f"gh api -X POST /repos/{bump_org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)", check=False)
|
||||
print(f" … Bump branch {bump_branch} does not exist. Creating it...")
|
||||
result = run_command(f"gh api -X POST /repos/{org_repo}/git/refs -f ref=refs/heads/{bump_branch} -f sha=$(gh api /repos/{org_repo}/git/refs/heads/{branch} --jq .object.sha)", check=False)
|
||||
if result.returncode != 0:
|
||||
print(f" ❌ Failed to create bump branch {bump_branch}")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
branch_created = True
|
||||
|
||||
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"]:
|
||||
latest_nightly = get_latest_nightly_tag(github_token)
|
||||
if latest_nightly:
|
||||
nightly_toolchain = f"leanprover/lean4:{latest_nightly}"
|
||||
print(f" ⮕ Updating lean-toolchain to {nightly_toolchain}...")
|
||||
if update_lean_toolchain_in_branch(bump_org_repo, bump_branch, nightly_toolchain, github_token):
|
||||
print(f" ✅ Updated lean-toolchain to {nightly_toolchain}")
|
||||
else:
|
||||
print(f" ❌ Failed to update lean-toolchain to {nightly_toolchain}")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
else:
|
||||
print(f" ❌ Could not fetch latest nightly tag")
|
||||
repo_status[name] = False
|
||||
continue
|
||||
if not check_bump_branch_toolchain(bump_url, bump_branch, github_token):
|
||||
if not check_bump_branch_toolchain(url, bump_branch, github_token):
|
||||
repo_status[name] = False
|
||||
continue
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
Execute release steps for Lean4 repositories.
|
||||
Generate release steps script for Lean4 repositories.
|
||||
|
||||
This script helps automate the release process for Lean4 and its dependent repositories
|
||||
by actually executing the step-by-step instructions for updating toolchains, creating tags,
|
||||
by generating step-by-step instructions for updating toolchains, creating tags,
|
||||
and managing branches.
|
||||
|
||||
Usage:
|
||||
@@ -12,11 +12,11 @@ Usage:
|
||||
|
||||
Arguments:
|
||||
version: The version to set in the lean-toolchain file (e.g., v4.6.0)
|
||||
repo: The repository name as specified in release_repos.yml
|
||||
repo: A substring of the repository name as specified in release_repos.yml
|
||||
|
||||
Example:
|
||||
python3 release_steps.py v4.6.0 mathlib4
|
||||
python3 release_steps.py v4.6.0 batteries
|
||||
python3 release_steps.py v4.6.0 mathlib
|
||||
python3 release_steps.py v4.6.0 batt
|
||||
|
||||
The script reads repository configurations from release_repos.yml in the same directory.
|
||||
Each repository may have specific requirements for:
|
||||
@@ -32,124 +32,23 @@ import yaml
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
import shutil
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
# Color functions for terminal output
|
||||
def blue(text):
|
||||
"""Blue text for 'I'm doing something' messages."""
|
||||
return f"\033[94m{text}\033[0m"
|
||||
|
||||
def green(text):
|
||||
"""Green text for 'successful step' messages."""
|
||||
return f"\033[92m{text}\033[0m"
|
||||
|
||||
def red(text):
|
||||
"""Red text for 'this looks bad' messages."""
|
||||
return f"\033[91m{text}\033[0m"
|
||||
|
||||
def yellow(text):
|
||||
"""Yellow text for warnings."""
|
||||
return f"\033[93m{text}\033[0m"
|
||||
|
||||
def run_command(cmd, cwd=None, check=True, stream_output=False):
|
||||
"""Run a shell command and return the result."""
|
||||
print(blue(f"Running: {cmd}"))
|
||||
try:
|
||||
if stream_output:
|
||||
# Stream output in real-time for long-running commands
|
||||
result = subprocess.run(cmd, shell=True, cwd=cwd, check=check, text=True)
|
||||
return result
|
||||
else:
|
||||
# Capture output for commands where we need to process the result
|
||||
result = subprocess.run(cmd, shell=True, cwd=cwd, check=check,
|
||||
capture_output=True, text=True)
|
||||
if result.stdout:
|
||||
# Command output in plain white (default terminal color)
|
||||
print(result.stdout)
|
||||
return result
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red(f"Error running command: {cmd}"))
|
||||
print(red(f"Exit code: {e.returncode}"))
|
||||
if not stream_output:
|
||||
print(f"Stdout: {e.stdout}")
|
||||
print(f"Stderr: {e.stderr}")
|
||||
raise
|
||||
|
||||
def load_repos_config(file_path):
|
||||
with open(file_path, "r") as f:
|
||||
return yaml.safe_load(f)["repositories"]
|
||||
|
||||
def find_repo(repo_name, config):
|
||||
matching_repos = [r for r in config if r["name"] == repo_name]
|
||||
def find_repo(repo_substring, config):
|
||||
pattern = re.compile(re.escape(repo_substring), re.IGNORECASE)
|
||||
matching_repos = [r for r in config if pattern.search(r["name"])]
|
||||
if not matching_repos:
|
||||
print(red(f"Error: No repository named '{repo_name}' found in configuration."))
|
||||
available_repos = [r["name"] for r in config]
|
||||
print(yellow(f"Available repositories: {', '.join(available_repos)}"))
|
||||
print(f"Error: No repository matching '{repo_substring}' found in configuration.")
|
||||
sys.exit(1)
|
||||
if len(matching_repos) > 1:
|
||||
print(f"Error: Multiple repositories matching '{repo_substring}' found in configuration: {', '.join(r['name'] for r in matching_repos)}")
|
||||
sys.exit(1)
|
||||
return matching_repos[0]
|
||||
|
||||
def setup_downstream_releases_dir():
|
||||
"""Create the downstream_releases directory if it doesn't exist."""
|
||||
downstream_dir = Path("downstream_releases")
|
||||
if not downstream_dir.exists():
|
||||
print(blue(f"Creating {downstream_dir} directory..."))
|
||||
downstream_dir.mkdir()
|
||||
print(green(f"Created {downstream_dir} directory"))
|
||||
return downstream_dir
|
||||
|
||||
def clone_or_update_repo(repo_url, repo_dir, downstream_dir):
|
||||
"""Clone the repository if it doesn't exist, or update it if it does."""
|
||||
repo_path = downstream_dir / repo_dir
|
||||
|
||||
if repo_path.exists():
|
||||
print(blue(f"Repository {repo_dir} already exists, updating..."))
|
||||
run_command("git fetch", cwd=repo_path)
|
||||
print(green(f"Updated repository {repo_dir}"))
|
||||
else:
|
||||
print(blue(f"Cloning {repo_url} to {repo_path}..."))
|
||||
run_command(f"git clone {repo_url}", cwd=downstream_dir)
|
||||
print(green(f"Cloned repository {repo_dir}"))
|
||||
|
||||
return repo_path
|
||||
|
||||
def get_remotes_for_repo(repo_name):
|
||||
"""Get the appropriate remotes for bump and nightly-testing branches based on repository."""
|
||||
if repo_name == "mathlib4":
|
||||
return "nightly-testing", "nightly-testing"
|
||||
else:
|
||||
return "origin", "origin"
|
||||
|
||||
def check_and_abort_merge(repo_path):
|
||||
"""Check if repository is in the middle of a merge and abort it if so."""
|
||||
merge_head_file = repo_path / ".git" / "MERGE_HEAD"
|
||||
|
||||
if merge_head_file.exists():
|
||||
print(yellow(f"Repository {repo_path.name} is in the middle of a merge. Aborting merge..."))
|
||||
run_command("git merge --abort", cwd=repo_path)
|
||||
print(green("Merge aborted successfully"))
|
||||
return True
|
||||
|
||||
# Also check git status for other merge-related states
|
||||
try:
|
||||
result = run_command("git status --porcelain=v1", cwd=repo_path, check=False)
|
||||
if result.returncode == 0:
|
||||
# Check for unmerged paths (indicated by 'UU', 'AA', etc. in git status)
|
||||
for line in result.stdout.splitlines():
|
||||
if len(line) >= 2 and line[:2] in ['UU', 'AA', 'DD', 'AU', 'UA', 'DU', 'UD']:
|
||||
print(yellow(f"Repository {repo_path.name} has unmerged paths. Aborting merge..."))
|
||||
run_command("git merge --abort", cwd=repo_path)
|
||||
print(green("Merge aborted successfully"))
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
# If git status fails, we'll let the main process handle it
|
||||
pass
|
||||
|
||||
return False
|
||||
|
||||
def execute_release_steps(repo, version, config):
|
||||
def generate_script(repo, version, config):
|
||||
repo_config = find_repo(repo, config)
|
||||
repo_name = repo_config['name']
|
||||
repo_url = repo_config['url']
|
||||
@@ -160,481 +59,92 @@ def execute_release_steps(repo, version, config):
|
||||
requires_tagging = repo_config.get("toolchain-tag", True)
|
||||
has_stable_branch = repo_config.get("stable-branch", True)
|
||||
|
||||
# Setup downstream releases directory
|
||||
downstream_dir = setup_downstream_releases_dir()
|
||||
|
||||
# Clone or update the repository
|
||||
repo_path = clone_or_update_repo(repo_url, repo_dir, downstream_dir)
|
||||
|
||||
# Special remote setup for mathlib4
|
||||
if repo_name == "mathlib4":
|
||||
print(blue("Setting up special remotes for mathlib4..."))
|
||||
try:
|
||||
# Check if nightly-testing remote already exists
|
||||
result = run_command("git remote get-url nightly-testing", cwd=repo_path, check=False)
|
||||
if result.returncode != 0:
|
||||
# Add the nightly-testing remote
|
||||
run_command("git remote add nightly-testing https://github.com/leanprover-community/mathlib4-nightly-testing.git", cwd=repo_path)
|
||||
print(green("Added nightly-testing remote"))
|
||||
else:
|
||||
print(green("nightly-testing remote already exists"))
|
||||
|
||||
# Fetch from the nightly-testing remote
|
||||
run_command("git fetch nightly-testing", cwd=repo_path)
|
||||
print(green("Fetched from nightly-testing remote"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red(f"Error setting up mathlib4 remotes: {e}"))
|
||||
print(yellow("Continuing with default remote setup..."))
|
||||
|
||||
print(blue(f"\n=== Executing release steps for {repo_name} ==="))
|
||||
|
||||
# Check if repository is in the middle of a merge and abort it if necessary
|
||||
check_and_abort_merge(repo_path)
|
||||
|
||||
# Execute the release steps
|
||||
run_command(f"git checkout {default_branch} && git pull", cwd=repo_path)
|
||||
|
||||
# Special rc1 safety check for batteries and mathlib4 (before creating any branches)
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["batteries", "mathlib4"] and version.endswith('-rc1'):
|
||||
print(blue("This repo has nightly-testing infrastructure"))
|
||||
print(blue(f"Checking if nightly-testing can be safely merged into bump/{version.split('-rc')[0]}..."))
|
||||
|
||||
# Get the base version (e.g., v4.6.0 from v4.6.0-rc1)
|
||||
base_version = version.split('-rc')[0]
|
||||
bump_branch = f"bump/{base_version}"
|
||||
|
||||
# Determine which remote to use for bump and nightly-testing branches
|
||||
bump_remote, nightly_remote = get_remotes_for_repo(repo_name)
|
||||
|
||||
try:
|
||||
# Fetch latest changes from the appropriate remote
|
||||
run_command(f"git fetch {bump_remote}", cwd=repo_path)
|
||||
|
||||
# Check if the bump branch exists
|
||||
result = run_command(f"git show-ref --verify --quiet refs/remotes/{bump_remote}/{bump_branch}", cwd=repo_path, check=False)
|
||||
if result.returncode != 0:
|
||||
print(red(f"Bump branch {bump_remote}/{bump_branch} does not exist. Cannot perform safety check."))
|
||||
print(yellow("Please ensure the bump branch exists before proceeding."))
|
||||
return
|
||||
|
||||
# Create a temporary branch for testing the merge
|
||||
temp_branch = f"temp-merge-test-{base_version}"
|
||||
|
||||
# Clean up any existing temp branch from previous runs
|
||||
result = run_command(f"git show-ref --verify --quiet refs/heads/{temp_branch}", cwd=repo_path, check=False)
|
||||
if result.returncode == 0:
|
||||
print(blue(f"Cleaning up existing temp branch {temp_branch}..."))
|
||||
# Make sure we're not on the temp branch before deleting it
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
print(green(f"Deleted existing temp branch {temp_branch}"))
|
||||
|
||||
run_command(f"git checkout -b {temp_branch} {bump_remote}/{bump_branch}", cwd=repo_path)
|
||||
|
||||
# Try to merge nightly-testing
|
||||
try:
|
||||
run_command(f"git merge {nightly_remote}/nightly-testing", cwd=repo_path)
|
||||
|
||||
# Check what files have changed compared to the bump branch
|
||||
changed_files = run_command(f"git diff --name-only {bump_remote}/{bump_branch}..HEAD", cwd=repo_path)
|
||||
|
||||
# Filter out allowed changes
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in changed_files.stdout.strip().split('\n'):
|
||||
if file.strip(): # Skip empty lines
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
# Clean up temporary branch and return to default branch
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
|
||||
if problematic_files:
|
||||
print(red("❌ Safety check failed!"))
|
||||
print(red(f"Merging nightly-testing into {bump_branch} would result in changes to:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(yellow("\nYou need to make a PR merging the changes from nightly-testing into the bump branch first."))
|
||||
print(yellow(f"Create a PR from nightly-testing targeting {bump_branch} to resolve these changes."))
|
||||
return
|
||||
else:
|
||||
print(green("✅ Safety check passed - only lean-toolchain and/or lake-manifest.json would change"))
|
||||
|
||||
except subprocess.CalledProcessError:
|
||||
# Merge failed due to conflicts - check which files are conflicted
|
||||
print(blue("Merge failed, checking which files are affected..."))
|
||||
|
||||
# Get all changed files using git status
|
||||
status_result = run_command("git status --porcelain", cwd=repo_path)
|
||||
changed_files = []
|
||||
|
||||
for line in status_result.stdout.splitlines():
|
||||
if line.strip(): # Skip empty lines
|
||||
# Extract filename (skip the first 3 characters which are status codes)
|
||||
changed_files.append(line[3:])
|
||||
|
||||
# Filter out allowed files
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in changed_files:
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
if problematic_files:
|
||||
# There are changes in non-allowed files - fail the safety check
|
||||
# First abort the merge to clean up the conflicted state
|
||||
run_command("git merge --abort", cwd=repo_path)
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
print(red("❌ Safety check failed!"))
|
||||
print(red(f"Merging nightly-testing into {bump_branch} would result in changes to:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(yellow("\nYou need to make a PR merging the changes from nightly-testing into the bump branch first."))
|
||||
print(yellow(f"Create a PR from nightly-testing targeting {bump_branch} to resolve these changes."))
|
||||
return
|
||||
else:
|
||||
# Only allowed files are changed - resolve them and continue
|
||||
print(green(f"✅ Only allowed files changed: {', '.join(changed_files)}"))
|
||||
print(blue("Resolving conflicts by taking nightly-testing version..."))
|
||||
|
||||
# For each changed allowed file, take the nightly-testing version
|
||||
for file in changed_files:
|
||||
run_command(f"git checkout --theirs {file}", cwd=repo_path)
|
||||
|
||||
# Complete the merge
|
||||
run_command("git add .", cwd=repo_path)
|
||||
run_command("git commit --no-edit", cwd=repo_path)
|
||||
|
||||
print(green("✅ Safety check passed - changes only in allowed files"))
|
||||
|
||||
# Clean up temporary branch and return to default branch
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
run_command(f"git branch -D {temp_branch}", cwd=repo_path)
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
# Ensure we're back on the default branch even if setup failed
|
||||
try:
|
||||
run_command(f"git checkout {default_branch}", cwd=repo_path)
|
||||
except subprocess.CalledProcessError:
|
||||
print(red(f"Cannot return to {default_branch} branch. Repository is in an inconsistent state."))
|
||||
print(red("Please manually check the repository state and fix any issues."))
|
||||
return
|
||||
print(red(f"Error during safety check: {e}"))
|
||||
print(yellow("Skipping safety check and proceeding with normal merge..."))
|
||||
|
||||
# Check if the branch already exists
|
||||
branch_name = f"bump_to_{version}"
|
||||
try:
|
||||
# Check if branch exists locally
|
||||
result = run_command(f"git show-ref --verify --quiet refs/heads/{branch_name}", cwd=repo_path, check=False)
|
||||
if result.returncode == 0:
|
||||
print(blue(f"Branch {branch_name} already exists, checking it out..."))
|
||||
run_command(f"git checkout {branch_name}", cwd=repo_path)
|
||||
print(green(f"Checked out existing branch {branch_name}"))
|
||||
else:
|
||||
print(blue(f"Creating new branch {branch_name}..."))
|
||||
run_command(f"git checkout -b {branch_name}", cwd=repo_path)
|
||||
print(green(f"Created new branch {branch_name}"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(blue(f"Creating new branch {branch_name}..."))
|
||||
run_command(f"git checkout -b {branch_name}", cwd=repo_path)
|
||||
print(green(f"Created new branch {branch_name}"))
|
||||
|
||||
# Update lean-toolchain
|
||||
print(blue("Updating lean-toolchain file..."))
|
||||
toolchain_file = repo_path / "lean-toolchain"
|
||||
with open(toolchain_file, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated lean-toolchain to leanprover/lean4:{version}"))
|
||||
script_lines = [
|
||||
f"cd {repo_dir}",
|
||||
"git fetch",
|
||||
f"git checkout {default_branch} && git pull",
|
||||
f"git checkout -b bump_to_{version}",
|
||||
f"echo leanprover/lean4:{version} > lean-toolchain",
|
||||
]
|
||||
|
||||
# Special cases for specific repositories
|
||||
if repo_name == "repl":
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
mathlib_test_dir = repo_path / "test" / "Mathlib"
|
||||
run_command(f'perl -pi -e \'s/rev = "v\\d+\\.\\d+\\.\\d+(-rc\\d+)?"/rev = "{version}"/g\' lakefile.toml', cwd=mathlib_test_dir)
|
||||
|
||||
# Update lean-toolchain in test/Mathlib
|
||||
print(blue("Updating test/Mathlib/lean-toolchain..."))
|
||||
mathlib_toolchain = mathlib_test_dir / "lean-toolchain"
|
||||
with open(mathlib_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated test/Mathlib/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
run_command("lake update", cwd=mathlib_test_dir, stream_output=True)
|
||||
try:
|
||||
result = run_command("./test.sh", cwd=repo_path, stream_output=True, check=False)
|
||||
if result.returncode == 0:
|
||||
print(green("Tests completed successfully"))
|
||||
else:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test exit code: {result.returncode}"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test error: {e}"))
|
||||
script_lines.extend([
|
||||
"lake update",
|
||||
"cd test/Mathlib",
|
||||
f"perl -pi -e 's/rev = \"v\\d+\\.\\d+\\.\\d+(-rc\\d+)?\"/rev = \"{version}\"/g' lakefile.toml",
|
||||
f"echo leanprover/lean4:{version} > lean-toolchain",
|
||||
"lake update",
|
||||
"cd ../..",
|
||||
"./test.sh"
|
||||
])
|
||||
elif dependencies:
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
script_lines.append('perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*')
|
||||
script_lines.append("lake update")
|
||||
|
||||
# Commit changes (only if there are changes)
|
||||
print(blue("Checking for changes to commit..."))
|
||||
try:
|
||||
# Check if there are any changes to commit (staged or unstaged)
|
||||
result = run_command("git status --porcelain", cwd=repo_path, check=False)
|
||||
if result.stdout.strip(): # There are changes
|
||||
print(blue("Committing changes..."))
|
||||
run_command(f'git commit -am "chore: bump toolchain to {version}"', cwd=repo_path)
|
||||
print(green(f"Committed changes: chore: bump toolchain to {version}"))
|
||||
else:
|
||||
print(green("No changes to commit - toolchain already up to date"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(yellow("Failed to check for changes, attempting commit anyway..."))
|
||||
try:
|
||||
run_command(f'git commit -am "chore: bump toolchain to {version}"', cwd=repo_path)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if "nothing to commit" in e.stderr:
|
||||
print(green("No changes to commit - toolchain already up to date"))
|
||||
else:
|
||||
raise
|
||||
script_lines.append("")
|
||||
|
||||
script_lines.extend([
|
||||
f'git commit -am "chore: bump toolchain to {version}"',
|
||||
""
|
||||
])
|
||||
|
||||
# Handle special merging cases
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["batteries", "mathlib4"]:
|
||||
print(blue("This repo uses `bump/v4.X.0` branches for reviewed content from nightly-testing."))
|
||||
|
||||
# Determine which remote to use for bump branches
|
||||
bump_remote, nightly_remote = get_remotes_for_repo(repo_name)
|
||||
|
||||
# Fetch latest changes to ensure we have the most up-to-date bump branch
|
||||
print(blue(f"Fetching latest changes from {bump_remote}..."))
|
||||
run_command(f"git fetch {bump_remote}", cwd=repo_path)
|
||||
|
||||
try:
|
||||
print(blue(f"Merging {bump_remote}/bump/{version.split('-rc')[0]}..."))
|
||||
run_command(f"git merge {bump_remote}/bump/{version.split('-rc')[0]}", cwd=repo_path)
|
||||
print(green("Merge completed successfully"))
|
||||
except subprocess.CalledProcessError:
|
||||
# Merge failed due to conflicts - check which files are conflicted
|
||||
print(blue("Merge conflicts detected, checking which files are affected..."))
|
||||
|
||||
# Get conflicted files using git status
|
||||
status_result = run_command("git status --porcelain", cwd=repo_path)
|
||||
conflicted_files = []
|
||||
|
||||
for line in status_result.stdout.splitlines():
|
||||
if len(line) >= 2 and line[:2] in ['UU', 'AA', 'DD', 'AU', 'UA', 'DU', 'UD']:
|
||||
# Extract filename (skip the first 3 characters which are status codes)
|
||||
conflicted_files.append(line[3:])
|
||||
|
||||
# Filter out allowed files
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in conflicted_files:
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
if problematic_files:
|
||||
# There are conflicts in non-allowed files - fail
|
||||
print(red("❌ Merge failed!"))
|
||||
print(red(f"Merging {bump_remote}/bump/{version.split('-rc')[0]} resulted in conflicts in:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(red("Please resolve these conflicts manually."))
|
||||
return
|
||||
else:
|
||||
# Only allowed files are conflicted - resolve them automatically
|
||||
print(green(f"✅ Only allowed files conflicted: {', '.join(conflicted_files)}"))
|
||||
print(blue("Resolving conflicts automatically..."))
|
||||
|
||||
# Overwrite lean-toolchain with our target version
|
||||
if 'lean-toolchain' in conflicted_files:
|
||||
print(blue(f"Overwriting lean-toolchain with target version {version}"))
|
||||
toolchain_file = repo_path / "lean-toolchain"
|
||||
with open(toolchain_file, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
|
||||
# For other allowed files, take our version (since we want our changes)
|
||||
for file in conflicted_files:
|
||||
if file != 'lean-toolchain':
|
||||
run_command(f"git checkout --ours {file}", cwd=repo_path)
|
||||
|
||||
# Run lake update to rebuild lake-manifest.json
|
||||
print(blue("Running lake update to rebuild lake-manifest.json..."))
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
|
||||
# Complete the merge
|
||||
run_command("git add .", cwd=repo_path)
|
||||
run_command("git commit --no-edit", cwd=repo_path)
|
||||
|
||||
print(green("✅ Merge completed successfully with automatic conflict resolution"))
|
||||
|
||||
elif re.search(r'rc\d+$', version):
|
||||
# For all other repos with rc versions, merge nightly-testing
|
||||
if repo_name in ["verso", "reference-manual"]:
|
||||
print(yellow("This repo does development on nightly-testing: remember to rebase merge the PR."))
|
||||
|
||||
# Fetch latest changes to ensure we have the most up-to-date nightly-testing branch
|
||||
print(blue("Fetching latest changes from origin..."))
|
||||
run_command("git fetch origin", cwd=repo_path)
|
||||
|
||||
try:
|
||||
print(blue("Merging origin/nightly-testing..."))
|
||||
run_command("git merge origin/nightly-testing", cwd=repo_path)
|
||||
print(green("Merge completed successfully"))
|
||||
except subprocess.CalledProcessError:
|
||||
# Merge failed due to conflicts - check which files are conflicted
|
||||
print(blue("Merge conflicts detected, checking which files are affected..."))
|
||||
|
||||
# Get conflicted files using git status
|
||||
status_result = run_command("git status --porcelain", cwd=repo_path)
|
||||
conflicted_files = []
|
||||
|
||||
for line in status_result.stdout.splitlines():
|
||||
if len(line) >= 2 and line[:2] in ['UU', 'AA', 'DD', 'AU', 'UA', 'DU', 'UD']:
|
||||
# Extract filename (skip the first 3 characters which are status codes)
|
||||
conflicted_files.append(line[3:])
|
||||
|
||||
# Filter out allowed files
|
||||
allowed_patterns = ['lean-toolchain', 'lake-manifest.json']
|
||||
problematic_files = []
|
||||
|
||||
for file in conflicted_files:
|
||||
is_allowed = any(pattern in file for pattern in allowed_patterns)
|
||||
if not is_allowed:
|
||||
problematic_files.append(file)
|
||||
|
||||
if problematic_files:
|
||||
# There are conflicts in non-allowed files - fail
|
||||
print(red("❌ Merge failed!"))
|
||||
print(red(f"Merging nightly-testing resulted in conflicts in:"))
|
||||
for file in problematic_files:
|
||||
print(red(f" - {file}"))
|
||||
print(red("Please resolve these conflicts manually."))
|
||||
return
|
||||
else:
|
||||
# Only allowed files are conflicted - resolve them automatically
|
||||
print(green(f"✅ Only allowed files conflicted: {', '.join(conflicted_files)}"))
|
||||
print(blue("Resolving conflicts automatically..."))
|
||||
|
||||
# For lean-toolchain and lake-manifest.json, keep our versions
|
||||
for file in conflicted_files:
|
||||
print(blue(f"Keeping our version of {file}"))
|
||||
run_command(f"git checkout --ours {file}", cwd=repo_path)
|
||||
|
||||
# Complete the merge
|
||||
run_command("git add .", cwd=repo_path)
|
||||
run_command("git commit --no-edit", cwd=repo_path)
|
||||
|
||||
print(green("✅ Merge completed successfully with automatic conflict resolution"))
|
||||
script_lines.extend([
|
||||
"echo 'This repo has nightly-testing infrastructure'",
|
||||
f"git merge origin/bump/{version.split('-rc')[0]}",
|
||||
"echo 'Please resolve any conflicts.'",
|
||||
"grep nightly-testing lakefile.* && echo 'Please ensure the lakefile does not include nightly-testing versions.'",
|
||||
""
|
||||
])
|
||||
if re.search(r'rc\d+$', version) and repo_name in ["verso", "reference-manual"]:
|
||||
script_lines.extend([
|
||||
"echo 'This repo does development on nightly-testing: remember to rebase merge the PR.'",
|
||||
f"git merge origin/nightly-testing",
|
||||
"echo 'Please resolve any conflicts.'",
|
||||
""
|
||||
])
|
||||
if repo_name != "Mathlib":
|
||||
script_lines.extend([
|
||||
"lake build && if lake check-test; then lake test; fi",
|
||||
""
|
||||
])
|
||||
|
||||
# Build and test (skip for Mathlib)
|
||||
if repo_name not in ["mathlib4"]:
|
||||
print(blue("Building project..."))
|
||||
|
||||
# Clean lake cache for a fresh build
|
||||
print(blue("Cleaning lake cache..."))
|
||||
run_command("rm -rf .lake", cwd=repo_path)
|
||||
|
||||
try:
|
||||
run_command("lake build", cwd=repo_path, stream_output=True)
|
||||
print(green("Build completed successfully"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Build failed, but continuing with PR creation..."))
|
||||
print(red(f"Build error: {e}"))
|
||||
|
||||
# Check if lake check-test exists before running tests
|
||||
print(blue("Running tests..."))
|
||||
check_test_result = run_command("lake check-test", cwd=repo_path, check=False)
|
||||
if check_test_result.returncode == 0:
|
||||
try:
|
||||
run_command("lake test", cwd=repo_path, stream_output=True)
|
||||
print(green("Tests completed successfully"))
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(red("Tests failed, but continuing with PR creation..."))
|
||||
print(red(f"Test error: {e}"))
|
||||
else:
|
||||
print(yellow("lake check-test reports that there is no test suite"))
|
||||
script_lines.extend([
|
||||
'gh pr create --title "chore: bump toolchain to ' + version + '" --body ""',
|
||||
"echo 'Please review the PR and merge or rebase it.'",
|
||||
""
|
||||
])
|
||||
|
||||
# Push the branch to remote before creating PR
|
||||
print(blue("Checking remote branch status..."))
|
||||
try:
|
||||
# Check if branch exists on remote
|
||||
result = run_command(f"git ls-remote --heads origin {branch_name}", cwd=repo_path, check=False)
|
||||
if not result.stdout.strip():
|
||||
print(blue(f"Pushing branch {branch_name} to remote..."))
|
||||
run_command(f"git push -u origin {branch_name}", cwd=repo_path)
|
||||
print(green(f"Successfully pushed branch {branch_name} to remote"))
|
||||
else:
|
||||
print(blue(f"Branch {branch_name} already exists on remote, pushing any new commits..."))
|
||||
run_command(f"git push", cwd=repo_path)
|
||||
print(green("Successfully pushed commits to remote"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(red("Failed to push branch to remote. Please check your permissions and network connection."))
|
||||
print(yellow(f"You may need to run: git push -u origin {branch_name}"))
|
||||
return
|
||||
|
||||
# Create pull request (only if one doesn't already exist)
|
||||
print(blue("Checking for existing pull request..."))
|
||||
try:
|
||||
# Check if PR already exists for this branch
|
||||
result = run_command(f'gh pr list --head {branch_name} --json number', cwd=repo_path, check=False)
|
||||
if result.returncode == 0 and result.stdout.strip() != "[]":
|
||||
print(green(f"Pull request already exists for branch {branch_name}"))
|
||||
# Get the PR URL
|
||||
pr_result = run_command(f'gh pr view {branch_name} --json url', cwd=repo_path, check=False)
|
||||
if pr_result.returncode == 0:
|
||||
pr_data = json.loads(pr_result.stdout)
|
||||
print(green(f"PR URL: {pr_data.get('url', 'N/A')}"))
|
||||
else:
|
||||
# Create new PR
|
||||
print(blue("Creating new pull request..."))
|
||||
run_command(f'gh pr create --title "chore: bump toolchain to {version}" --body ""', cwd=repo_path)
|
||||
print(green("Pull request created successfully!"))
|
||||
except subprocess.CalledProcessError:
|
||||
print(red("Failed to check for existing PR or create new PR."))
|
||||
print(yellow("This could be due to:"))
|
||||
print(yellow("1. GitHub CLI not authenticated"))
|
||||
print(yellow("2. No push permissions to the repository"))
|
||||
print(yellow("3. Network issues"))
|
||||
print(f"Branch: {branch_name}")
|
||||
print(f"Title: chore: bump toolchain to {version}")
|
||||
print(yellow("Please create the PR manually if needed."))
|
||||
return "\n".join(script_lines)
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Execute release steps for Lean4 repositories.",
|
||||
description="Generate release steps script for Lean4 repositories.",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
%(prog)s v4.6.0 mathlib4 Execute steps for updating Mathlib to v4.6.0
|
||||
%(prog)s v4.6.0 batteries Execute steps for updating Batteries to v4.6.0
|
||||
%(prog)s v4.6.0 mathlib Generate steps for updating Mathlib to v4.6.0
|
||||
%(prog)s v4.6.0 batt Generate steps for updating Batteries to v4.6.0
|
||||
|
||||
The script will:
|
||||
1. Create a downstream_releases/ directory
|
||||
2. Clone or update the target repository
|
||||
3. Update the lean-toolchain file
|
||||
4. Create appropriate branches and commits
|
||||
5. Build and test the project
|
||||
6. Create pull requests
|
||||
The script will generate shell commands to:
|
||||
1. Update the lean-toolchain file
|
||||
2. Create appropriate branches and commits
|
||||
3. Create pull requests
|
||||
|
||||
(Note that the steps of creating toolchain version tags, and merging these into `stable` branches,
|
||||
are handled by `script/release_checklist.py`.)
|
||||
"""
|
||||
)
|
||||
parser.add_argument("version", help="The version to set in the lean-toolchain file (e.g., v4.6.0)")
|
||||
parser.add_argument("repo", help="The repository name as specified in release_repos.yml")
|
||||
parser.add_argument("repo", help="A substring of the repository name as specified in release_repos.yml")
|
||||
args = parser.parse_args()
|
||||
|
||||
config_path = os.path.join(os.path.dirname(__file__), "release_repos.yml")
|
||||
config = load_repos_config(config_path)
|
||||
|
||||
execute_release_steps(args.repo, args.version, config)
|
||||
script = generate_script(args.repo, args.version, config)
|
||||
print(script)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 23)
|
||||
set(LEAN_VERSION_MINOR 22)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
|
||||
@@ -6,41 +6,41 @@ Authors: Leonardo de Moura
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Prelude
|
||||
public import Init.Notation
|
||||
public import Init.Tactics
|
||||
public import Init.TacticsExtra
|
||||
public import Init.ByCases
|
||||
public import Init.RCases
|
||||
public import Init.Core
|
||||
public import Init.Control
|
||||
public import Init.Data.Basic
|
||||
public import Init.WF
|
||||
public import Init.WFTactics
|
||||
public import Init.Data
|
||||
public import Init.System
|
||||
public import Init.Util
|
||||
public import Init.Dynamic
|
||||
public import Init.ShareCommon
|
||||
public import Init.MetaTypes
|
||||
public import Init.Meta
|
||||
public import Init.NotationExtra
|
||||
public import Init.SimpLemmas
|
||||
public import Init.PropLemmas
|
||||
public import Init.Hints
|
||||
public import Init.Conv
|
||||
public import Init.Guard
|
||||
public import Init.Simproc
|
||||
public import Init.SizeOfLemmas
|
||||
public import Init.BinderPredicates
|
||||
public import Init.Ext
|
||||
public import Init.Omega
|
||||
public import Init.MacroTrace
|
||||
public import Init.Grind
|
||||
public import Init.GrindInstances
|
||||
public import Init.While
|
||||
public import Init.Syntax
|
||||
public import Init.Internal
|
||||
public import Init.Try
|
||||
public import Init.BinderNameHint
|
||||
public import Init.Task
|
||||
import Init.Prelude
|
||||
import Init.Notation
|
||||
import Init.Tactics
|
||||
import Init.TacticsExtra
|
||||
import Init.ByCases
|
||||
import Init.RCases
|
||||
import Init.Core
|
||||
import Init.Control
|
||||
import Init.Data.Basic
|
||||
import Init.WF
|
||||
import Init.WFTactics
|
||||
import Init.Data
|
||||
import Init.System
|
||||
import Init.Util
|
||||
import Init.Dynamic
|
||||
import Init.ShareCommon
|
||||
import Init.MetaTypes
|
||||
import Init.Meta
|
||||
import Init.NotationExtra
|
||||
import Init.SimpLemmas
|
||||
import Init.PropLemmas
|
||||
import Init.Hints
|
||||
import Init.Conv
|
||||
import Init.Guard
|
||||
import Init.Simproc
|
||||
import Init.SizeOfLemmas
|
||||
import Init.BinderPredicates
|
||||
import Init.Ext
|
||||
import Init.Omega
|
||||
import Init.MacroTrace
|
||||
import Init.Grind
|
||||
import Init.GrindInstances
|
||||
import Init.While
|
||||
import Init.Syntax
|
||||
import Init.Internal
|
||||
import Init.Try
|
||||
import Init.BinderNameHint
|
||||
import Init.Task
|
||||
|
||||
@@ -323,7 +323,7 @@ macro_rules
|
||||
| `(conv| repeat $seq) => `(conv| first | ($seq); repeat $seq | skip)
|
||||
|
||||
/--
|
||||
Extracts `let` and `have` expressions from within the target expression.
|
||||
Extracts `let` and `let_fun` expressions from within the target expression.
|
||||
This is the conv mode version of the `extract_lets` tactic.
|
||||
|
||||
- `extract_lets` extracts all the lets from the target.
|
||||
@@ -336,7 +336,7 @@ See also `lift_lets`, which does not extract lets as local declarations.
|
||||
syntax (name := extractLets) "extract_lets " optConfig (ppSpace colGt (ident <|> hole))* : conv
|
||||
|
||||
/--
|
||||
Lifts `let` and `have` expressions within the target expression as far out as possible.
|
||||
Lifts `let` and `let_fun` expressions within the target expression as far out as possible.
|
||||
This is the conv mode version of the `lift_lets` tactic.
|
||||
-/
|
||||
syntax (name := liftLets) "lift_lets " optConfig : conv
|
||||
|
||||
@@ -180,7 +180,7 @@ in-place when the reference to the array is unique.
|
||||
|
||||
This avoids overhead due to unboxing a `Nat` used as an index.
|
||||
-/
|
||||
@[extern "lean_array_uset", expose]
|
||||
@[extern "lean_array_uset"]
|
||||
def uset (xs : Array α) (i : USize) (v : α) (h : i.toNat < xs.size) : Array α :=
|
||||
xs.set i.toNat v h
|
||||
|
||||
@@ -263,7 +263,7 @@ Examples:
|
||||
* `#["red", "green", "blue", "brown"].swapIfInBounds 0 4 = #["red", "green", "blue", "brown"]`
|
||||
* `#["red", "green", "blue", "brown"].swapIfInBounds 9 2 = #["red", "green", "blue", "brown"]`
|
||||
-/
|
||||
@[extern "lean_array_swap", grind]
|
||||
@[extern "lean_array_swap"]
|
||||
def swapIfInBounds (xs : Array α) (i j : @& Nat) : Array α :=
|
||||
if h₁ : i < xs.size then
|
||||
if h₂ : j < xs.size then swap xs i j
|
||||
@@ -1024,7 +1024,7 @@ The optional parameters `start` and `stop` control the region of the array to wh
|
||||
applied. Iteration proceeds from `start` (inclusive) to `stop` (exclusive), so `f` is not invoked
|
||||
unless `start < stop`. By default, the entire array is used.
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline]
|
||||
protected def forM {α : Type u} {m : Type v → Type w} [Monad m] (f : α → m PUnit) (as : Array α) (start := 0) (stop := as.size) : m PUnit :=
|
||||
as.foldlM (fun _ => f) ⟨⟩ start stop
|
||||
|
||||
@@ -1808,7 +1808,6 @@ Examples:
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 3 = #["apple", "pear", "orange"]`
|
||||
* `#["apple", "pear", "orange"].eraseIdxIfInBounds 5 = #["apple", "pear", "orange"]`
|
||||
-/
|
||||
@[grind]
|
||||
def eraseIdxIfInBounds (xs : Array α) (i : Nat) : Array α :=
|
||||
if h : i < xs.size then xs.eraseIdx i h else xs
|
||||
|
||||
@@ -1919,7 +1918,6 @@ Examples:
|
||||
* `#["tues", "thur", "sat"].insertIdxIfInBounds 3 "wed" = #["tues", "thur", "sat", "wed"]`
|
||||
* `#["tues", "thur", "sat"].insertIdxIfInBounds 4 "wed" = #["tues", "thur", "sat"]`
|
||||
-/
|
||||
@[grind]
|
||||
def insertIdxIfInBounds (as : Array α) (i : Nat) (a : α) : Array α :=
|
||||
if h : i ≤ as.size then
|
||||
insertIdx as i a
|
||||
|
||||
@@ -387,7 +387,7 @@ theorem find?_eq_some_iff_getElem {xs : Array α} {p : α → Bool} {b : α} :
|
||||
/-! ### findIdx -/
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_empty : findIdx p #[] = 0 := by simp
|
||||
theorem findIdx_empty : findIdx p #[] = 0 := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem findIdx_singleton {a : α} {p : α → Bool} :
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace Array
|
||||
@[simp, grind =] theorem le_toList [LT α] {xs ys : Array α} : xs.toList ≤ ys.toList ↔ xs ≤ ys := Iff.rfl
|
||||
|
||||
protected theorem not_lt_iff_ge [LT α] {xs ys : Array α} : ¬ xs < ys ↔ ys ≤ xs := Iff.rfl
|
||||
protected theorem not_le_iff_gt [LT α] {xs ys : Array α} :
|
||||
protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {xs ys : Array α} :
|
||||
¬ xs ≤ ys ↔ ys < xs :=
|
||||
Classical.not_not
|
||||
Decidable.not_not
|
||||
|
||||
@[simp] theorem lex_empty [BEq α] {lt : α → α → Bool} {xs : Array α} : xs.lex #[] lt = false := by
|
||||
simp [lex]
|
||||
@@ -94,7 +94,7 @@ instance [LT α] [Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
Trans (· < · : Array α → Array α → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := Array.lt_trans h₁ h₂
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α]
|
||||
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -102,7 +102,7 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys < zs) : xs < zs :=
|
||||
List.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [LT α]
|
||||
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -110,7 +110,7 @@ protected theorem le_trans [LT α]
|
||||
{xs ys zs : Array α} (h₁ : xs ≤ ys) (h₂ : ys ≤ zs) : xs ≤ zs :=
|
||||
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -122,34 +122,34 @@ protected theorem lt_asymm [LT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Array α} (h : xs < ys) : ¬ ys < xs := List.lt_asymm h
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Asymm (· < · : Array α → Array α → Prop) where
|
||||
asymm _ _ := Array.lt_asymm
|
||||
|
||||
protected theorem le_total [LT α]
|
||||
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] (xs ys : Array α) : xs ≤ ys ∨ ys ≤ xs :=
|
||||
List.le_total xs.toList ys.toList
|
||||
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
{xs ys : Array α} : ¬ xs < ys ↔ ys ≤ xs := Iff.rfl
|
||||
|
||||
@[simp] protected theorem not_le [LT α]
|
||||
{xs ys : Array α} : ¬ ys ≤ xs ↔ xs < ys := Classical.not_not
|
||||
@[simp] protected theorem not_le [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Array α} : ¬ ys ≤ xs ↔ xs < ys := Decidable.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
protected theorem le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)]
|
||||
{xs ys : Array α} (h : xs < ys) : xs ≤ ys :=
|
||||
List.le_of_lt h
|
||||
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Total (¬ · < · : α → α → Prop)]
|
||||
{xs ys : Array α} : xs ≤ ys ↔ xs < ys ∨ xs = ys := by
|
||||
simpa using List.le_iff_lt_or_eq (l₁ := xs.toList) (l₂ := ys.toList)
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : Array α → Array α → Prop) where
|
||||
total := Array.le_total
|
||||
@@ -218,7 +218,7 @@ theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α → α
|
||||
cases l₂
|
||||
simp_all [List.lex_eq_false_iff_exists]
|
||||
|
||||
protected theorem lt_iff_exists [LT α] {xs ys : Array α} :
|
||||
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {xs ys : Array α} :
|
||||
xs < ys ↔
|
||||
(xs = ys.take xs.size ∧ xs.size < ys.size) ∨
|
||||
(∃ (i : Nat) (h₁ : i < xs.size) (h₂ : i < ys.size),
|
||||
@@ -228,7 +228,7 @@ protected theorem lt_iff_exists [LT α] {xs ys : Array α} :
|
||||
cases ys
|
||||
simp [List.lt_iff_exists]
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
protected theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {xs ys : Array α} :
|
||||
@@ -248,7 +248,7 @@ theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
|
||||
cases zs
|
||||
simpa using List.append_left_lt h
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
theorem append_left_le [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -272,7 +272,7 @@ protected theorem map_lt [LT α] [LT β]
|
||||
cases ys
|
||||
simpa using List.map_lt w h
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq β] [LT β] [DecidableLT β]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
|
||||
@@ -35,12 +35,7 @@ protected def ofNatLt {n : Nat} (i : Nat) (p : i < 2 ^ n) : BitVec n :=
|
||||
|
||||
section Nat
|
||||
|
||||
/--
|
||||
`NatCast` instance for `BitVec`.
|
||||
-/
|
||||
-- As this is a lossy conversion, it should be removed as a global instance.
|
||||
instance instNatCast : NatCast (BitVec w) where
|
||||
natCast x := BitVec.ofNat w x
|
||||
instance natCastInst : NatCast (BitVec w) := ⟨BitVec.ofNat w⟩
|
||||
|
||||
/-- Theorem for normalizing the bitvector literal representation. -/
|
||||
-- TODO: This needs more usage data to assess which direction the simp should go.
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Array.DecidableEq
|
||||
public import Init.Data.UInt.Basic
|
||||
public import all Init.Data.UInt.BasicAux
|
||||
public import Init.Data.Option.Basic
|
||||
@@ -22,14 +21,6 @@ attribute [extern "lean_byte_array_mk"] ByteArray.mk
|
||||
attribute [extern "lean_byte_array_data"] ByteArray.data
|
||||
|
||||
namespace ByteArray
|
||||
|
||||
deriving instance BEq for ByteArray
|
||||
|
||||
attribute [ext] ByteArray
|
||||
|
||||
instance : DecidableEq ByteArray :=
|
||||
fun _ _ => decidable_of_decidable_of_iff ByteArray.ext_iff.symm
|
||||
|
||||
@[extern "lean_mk_empty_byte_array"]
|
||||
def emptyWithCapacity (c : @& Nat) : ByteArray :=
|
||||
{ data := #[] }
|
||||
|
||||
@@ -185,9 +185,7 @@ theorem foldrM_loop [Monad m] [LawfulMonad m] (f : Fin (n+1) → α → m α) (x
|
||||
| zero =>
|
||||
rw [foldrM_loop_zero, foldrM_loop_succ, pure_bind]
|
||||
conv => rhs; rw [←bind_pure (f 0 x)]
|
||||
congr
|
||||
funext
|
||||
rw [foldrM_loop_zero]
|
||||
rfl
|
||||
| succ i ih =>
|
||||
rw [foldrM_loop_succ, foldrM_loop_succ, bind_assoc]
|
||||
congr; funext; exact ih ..
|
||||
|
||||
@@ -9,8 +9,6 @@ prelude
|
||||
public import Init.Data.Array.Basic
|
||||
public import Init.Data.Float
|
||||
public import Init.Data.Option.Basic
|
||||
import Init.Ext
|
||||
public import Init.Data.Array.DecidableEq
|
||||
|
||||
public section
|
||||
universe u
|
||||
@@ -22,11 +20,6 @@ attribute [extern "lean_float_array_mk"] FloatArray.mk
|
||||
attribute [extern "lean_float_array_data"] FloatArray.data
|
||||
|
||||
namespace FloatArray
|
||||
|
||||
deriving instance BEq for FloatArray
|
||||
|
||||
attribute [ext] FloatArray
|
||||
|
||||
@[extern "lean_mk_empty_float_array"]
|
||||
def emptyWithCapacity (c : @& Nat) : FloatArray :=
|
||||
{ data := #[] }
|
||||
|
||||
@@ -425,10 +425,6 @@ expectation that the resulting string is valid code.
|
||||
The `Repr` class is similar, but the expectation is that instances produce valid Lean code.
|
||||
-/
|
||||
class ToFormat (α : Type u) where
|
||||
/--
|
||||
Converts a value to a `Format` object, with no expectation that the resulting string is valid
|
||||
code.
|
||||
-/
|
||||
format : α → Format
|
||||
|
||||
export ToFormat (format)
|
||||
|
||||
@@ -1524,7 +1524,7 @@ private theorem cooper_right_core
|
||||
have d_pos : (0 : Int) < 1 := by decide
|
||||
have h₃ : 1 ∣ 0*x + 0 := Int.one_dvd _
|
||||
have h := cooper_dvd_right_core a_neg b_pos d_pos h₁ h₂ h₃
|
||||
simp only [Int.mul_one, gcd_zero, Int.natAbs_of_nonneg (Int.le_of_lt b_pos),
|
||||
simp only [Int.mul_one, gcd_zero, Int.natAbs_of_nonneg (Int.le_of_lt b_pos),
|
||||
Int.ediv_self (Int.ne_of_gt b_pos), lcm_one,
|
||||
Int.zero_mul, Int.mul_zero, Int.add_zero, Int.dvd_zero,
|
||||
and_true, Int.neg_zero] at h
|
||||
@@ -1915,11 +1915,6 @@ theorem eq_def (ctx : Context) (x : Var) (xPoly : Poly) (p : Poly)
|
||||
simp [eq_def_cert]; intro _ h; subst p; simp [h]
|
||||
rw [← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
theorem eq_def_norm (ctx : Context) (x : Var) (xPoly xPoly' : Poly) (p : Poly)
|
||||
: eq_def_cert x xPoly' p → x.denote ctx = xPoly.denote' ctx → xPoly.denote' ctx = xPoly'.denote' ctx → p.denote' ctx = 0 := by
|
||||
simp [eq_def_cert]; intro _ h₁ h₂; subst p; simp [h₁, h₂]
|
||||
rw [← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
@[expose]
|
||||
def eq_def'_cert (x : Var) (e : Expr) (p : Poly) : Bool :=
|
||||
p == .add (-1) x e.norm
|
||||
@@ -1929,27 +1924,6 @@ theorem eq_def' (ctx : Context) (x : Var) (e : Expr) (p : Poly)
|
||||
simp [eq_def'_cert]; intro _ h; subst p; simp [h]
|
||||
rw [← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
@[expose]
|
||||
def eq_def'_norm_cert (x : Var) (e : Expr) (ePoly ePoly' p : Poly) : Bool :=
|
||||
ePoly == e.norm && p == .add (-1) x ePoly'
|
||||
|
||||
theorem eq_def'_norm (ctx : Context) (x : Var) (e : Expr) (ePoly ePoly' : Poly) (p : Poly)
|
||||
: eq_def'_norm_cert x e ePoly ePoly' p → x.denote ctx = e.denote ctx → ePoly.denote' ctx = ePoly'.denote' ctx → p.denote' ctx = 0 := by
|
||||
simp [eq_def'_norm_cert]; intro _ _ h₁ h₂; subst ePoly p; simp [h₁, ← h₂]
|
||||
rw [← Int.sub_eq_add_neg, Int.sub_self]
|
||||
|
||||
theorem eq_norm_poly (ctx : Context) (p p' : Poly) : p.denote' ctx = p'.denote' ctx → p.denote' ctx = 0 → p'.denote' ctx = 0 := by
|
||||
intro h; rw [h]; simp
|
||||
|
||||
theorem le_norm_poly (ctx : Context) (p p' : Poly) : p.denote' ctx = p'.denote' ctx → p.denote' ctx ≤ 0 → p'.denote' ctx ≤ 0 := by
|
||||
intro h; rw [h]; simp
|
||||
|
||||
theorem diseq_norm_poly (ctx : Context) (p p' : Poly) : p.denote' ctx = p'.denote' ctx → p.denote' ctx ≠ 0 → p'.denote' ctx ≠ 0 := by
|
||||
intro h; rw [h]; simp
|
||||
|
||||
theorem dvd_norm_poly (ctx : Context) (d : Int) (p p' : Poly) : p.denote' ctx = p'.denote' ctx → d ∣ p.denote' ctx → d ∣ p'.denote' ctx := by
|
||||
intro h; rw [h]; simp
|
||||
|
||||
end Int.Linear
|
||||
|
||||
theorem Int.not_le_eq (a b : Int) : (¬a ≤ b) = (b + 1 ≤ a) := by
|
||||
|
||||
@@ -98,12 +98,12 @@ instance Attach.instIteratorCollectPartial {α β : Type w} {m : Type w → Type
|
||||
.defaultImplementation
|
||||
|
||||
instance Attach.instIteratorLoop {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
{n : Type x → Type x'} [Monad n] {P : β → Prop} [Iterator α m β] :
|
||||
[Monad n] {P : β → Prop} [Iterator α m β] [MonadLiftT m n] :
|
||||
IteratorLoop (Attach α m P) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Attach.instIteratorLoopPartial {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
{n : Type x → Type x'} [Monad n] {P : β → Prop} [Iterator α m β] :
|
||||
[Monad n] {P : β → Prop} [Iterator α m β] [MonadLiftT m n] :
|
||||
IteratorLoopPartial (Attach α m P) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
|
||||
@@ -231,14 +231,14 @@ instance {α β γ : Type w} {m : Type w → Type w'}
|
||||
.defaultImplementation
|
||||
|
||||
instance FilterMap.instIteratorLoop {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Monad n] [Monad o] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} [Finite α m] :
|
||||
IteratorLoop (FilterMap α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance FilterMap.instIteratorLoopPartial {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Monad n] [Monad o] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} :
|
||||
IteratorLoopPartial (FilterMap α m n lift f) n o :=
|
||||
@@ -274,14 +274,14 @@ instance Map.instIteratorCollectPartial {α β γ : Type w} {m : Type w → Type
|
||||
it.internalState.inner (m := m)
|
||||
|
||||
instance Map.instIteratorLoop {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'} [Monad n] [Monad o] [Iterator α m β]
|
||||
{n : Type w → Type w''} {o : Type w → Type x} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} :
|
||||
IteratorLoop (Map α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Map.instIteratorLoopPartial {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'} [Monad n] [Monad o] [Iterator α m β]
|
||||
{n : Type w → Type w''} {o : Type w → Type x} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} :
|
||||
IteratorLoopPartial (Map α m n lift f) n o :=
|
||||
|
||||
@@ -123,16 +123,15 @@ instance Types.ULiftIterator.instProductive [Iterator α m β] [Productive α m]
|
||||
Productive (ULiftIterator α m n β lift) n :=
|
||||
.of_productivenessRelation instProductivenessRelation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorLoop {o : Type x → Type x'} [Monad n] [Monad o]
|
||||
[Iterator α m β] :
|
||||
instance Types.ULiftIterator.instIteratorLoop {o} [Monad n] [Monad o] [Iterator α m β] :
|
||||
IteratorLoop (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorLoopPartial {o : Type x → Type x'} [Monad n] [Monad o] [Iterator α m β] :
|
||||
instance Types.ULiftIterator.instIteratorLoopPartial {o} [Monad n] [Monad o] [Iterator α m β] :
|
||||
IteratorLoopPartial (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorCollect [Monad n] [Monad o] [Iterator α m β] :
|
||||
instance Types.ULiftIterator.instIteratorCollect {o} [Monad n] [Monad o] [Iterator α m β] :
|
||||
IteratorCollect (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
|
||||
@@ -33,42 +33,32 @@ so this is not marked as `instance`. This way, more convenient instances can be
|
||||
or future library improvements will make it more comfortable.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||||
def Iter.instForIn' {α : Type w} {β : Type w} {n : Type w → Type w'} [Monad n]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id n] :
|
||||
ForIn' n (Iter (α := α) β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f :=
|
||||
IteratorLoop.finiteForIn' (fun _ _ f c => f c.run) |>.forIn' it.toIterM init
|
||||
IteratorLoop.finiteForIn' (fun δ (c : Id δ) => pure c.run) |>.forIn' it.toIterM init
|
||||
fun out h acc =>
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc
|
||||
|
||||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||||
instance (α : Type w) (β : Type w) (n : Type w → Type w') [Monad n]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id n] :
|
||||
ForIn n (Iter (α := α) β) β :=
|
||||
haveI : ForIn' n (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
@[always_inline, inline]
|
||||
def Iter.Partial.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||||
instance (α : Type w) (β : Type w) (n : Type w → Type w') [Monad n]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id n] :
|
||||
ForIn' n (Iter.Partial (α := α) β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f :=
|
||||
IteratorLoopPartial.forInPartial (α := α) (m := Id) (n := n) (fun _ _ f c => f c.run)
|
||||
it.it.toIterM init
|
||||
fun out h acc =>
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc
|
||||
ForIn n (Iter.Partial (α := α) β) β where
|
||||
forIn it init f :=
|
||||
ForIn.forIn it.it.toIterM.allowNontermination init f
|
||||
|
||||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id n] :
|
||||
ForIn n (Iter.Partial (α := α) β) β :=
|
||||
haveI : ForIn' n (Iter.Partial (α := α) β) β _ := Iter.Partial.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
instance {m : Type x → Type x'}
|
||||
instance {m : Type w → Type w'}
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id m] :
|
||||
ForM m (Iter (α := α) β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
instance {m : Type x → Type x'}
|
||||
instance {m : Type w → Type w'}
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoopPartial α Id m] :
|
||||
ForM m (Iter.Partial (α := α) β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
@@ -85,8 +75,8 @@ number of steps. If the iterator is not finite or such an instance is not availa
|
||||
verify the behavior of the partial variant.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.foldM {m : Type x → Type x'} [Monad m]
|
||||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
def Iter.foldM {m : Type w → Type w'} [Monad m]
|
||||
{α : Type w} {β : Type w} {γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id m] (f : γ → β → m γ)
|
||||
(init : γ) (it : Iter (α := α) β) : m γ :=
|
||||
ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x)
|
||||
@@ -101,8 +91,8 @@ This is a partial, potentially nonterminating, function. It is not possible to f
|
||||
its behavior. If the iterator has a `Finite` instance, consider using `IterM.foldM` instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Partial.foldM {m : Type x → Type x'} [Monad m]
|
||||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
def Iter.Partial.foldM {m : Type w → Type w'} [Monad m]
|
||||
{α : Type w} {β : Type w} {γ : Type w} [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id m] (f : γ → β → m γ)
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : m γ :=
|
||||
ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x)
|
||||
@@ -119,7 +109,7 @@ number of steps. If the iterator is not finite or such an instance is not availa
|
||||
verify the behavior of the partial variant.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
def Iter.fold {α : Type w} {β : Type w} {γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] (f : γ → β → γ)
|
||||
(init : γ) (it : Iter (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
@@ -134,7 +124,7 @@ This is a partial, potentially nonterminating, function. It is not possible to f
|
||||
its behavior. If the iterator has a `Finite` instance, consider using `IterM.fold` instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type w} [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id Id] (f : γ → β → γ)
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
|
||||
@@ -62,8 +62,8 @@ They can, however, assume that consumers that require an instance will work for
|
||||
provided by the standard library.
|
||||
-/
|
||||
class IteratorLoop (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β]
|
||||
(n : Type x → Type x') where
|
||||
forIn : ∀ (_liftBind : (γ : Type w) → (δ : Type x) → (γ → n δ) → m γ → n δ) (γ : Type x),
|
||||
(n : Type w → Type w'') where
|
||||
forIn : ∀ (_lift : (γ : Type w) → m γ → n γ) (γ : Type w),
|
||||
(plausible_forInStep : β → γ → ForInStep γ → Prop) →
|
||||
IteratorLoop.WellFounded α m plausible_forInStep →
|
||||
(it : IterM (α := α) m β) → γ →
|
||||
@@ -79,8 +79,8 @@ They can, however, assume that consumers that require an instance will work for
|
||||
provided by the standard library.
|
||||
-/
|
||||
class IteratorLoopPartial (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β]
|
||||
(n : Type x → Type x') where
|
||||
forInPartial : ∀ (_liftBind : (γ : Type w) → (δ : Type x) → (γ → n δ) → m γ → n δ) {γ : Type x},
|
||||
(n : Type w → Type w'') where
|
||||
forInPartial : ∀ (_lift : (γ : Type w) → m γ → n γ) {γ : Type w},
|
||||
(it : IterM (α := α) m β) → γ →
|
||||
((b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (ForInStep γ)) → n γ
|
||||
|
||||
@@ -133,25 +133,27 @@ This is the loop implementation of the default instance `IteratorLoop.defaultImp
|
||||
@[specialize]
|
||||
def IterM.DefaultConsumers.forIn' {m : Type w → Type w'} {α : Type w} {β : Type w}
|
||||
[Iterator α m β]
|
||||
{n : Type x → Type x'} [Monad n]
|
||||
(lift : ∀ γ δ, (γ → n δ) → m γ → n δ) (γ : Type x)
|
||||
{n : Type w → Type w''} [Monad n]
|
||||
(lift : ∀ γ, m γ → n γ) (γ : Type w)
|
||||
(plausible_forInStep : β → γ → ForInStep γ → Prop)
|
||||
(wf : IteratorLoop.WellFounded α m plausible_forInStep)
|
||||
(it : IterM (α := α) m β) (init : γ)
|
||||
(P : β → Prop) (hP : ∀ b, it.IsPlausibleIndirectOutput b → P b)
|
||||
(f : (b : β) → P b → (c : γ) → n (Subtype (plausible_forInStep b c))) : n γ :=
|
||||
haveI : WellFounded _ := wf
|
||||
(lift _ _ · it.step) fun
|
||||
| .yield it' out h => do
|
||||
match ← f out (hP _ <| .direct ⟨_, h⟩) init with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' c P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| ⟨.done c, _⟩ => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' init P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| .done _ => return init
|
||||
letI : MonadLift m n := ⟨fun {γ} => lift γ⟩
|
||||
do
|
||||
match ← it.step with
|
||||
| .yield it' out h =>
|
||||
match ← f out (hP _ <| .direct ⟨_, h⟩) init with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' c P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| ⟨.done c, _⟩ => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' init P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| .done _ => return init
|
||||
termination_by IteratorLoop.WFRel.mk wf it init
|
||||
decreasing_by
|
||||
· exact Or.inl ⟨out, ‹_›, ‹_›⟩
|
||||
@@ -163,7 +165,7 @@ It simply iterates through the iterator using `IterM.step`. For certain iterator
|
||||
implementations are possible and should be used instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IteratorLoop.defaultImplementation {α : Type w} {m : Type w → Type w'} {n : Type x → Type x'}
|
||||
def IteratorLoop.defaultImplementation {α : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
[Monad n] [Iterator α m β] :
|
||||
IteratorLoop α m n where
|
||||
forIn lift γ Pl wf it init := IterM.DefaultConsumers.forIn' lift γ Pl wf it init _ (fun _ => id)
|
||||
@@ -172,7 +174,7 @@ def IteratorLoop.defaultImplementation {α : Type w} {m : Type w → Type w'} {n
|
||||
Asserts that a given `IteratorLoop` instance is equal to `IteratorLoop.defaultImplementation`.
|
||||
(Even though equal, the given instance might be vastly more efficient.)
|
||||
-/
|
||||
class LawfulIteratorLoop (α : Type w) (m : Type w → Type w') (n : Type x → Type x')
|
||||
class LawfulIteratorLoop (α : Type w) (m : Type w → Type w') (n : Type w → Type w'')
|
||||
[Monad n] [Iterator α m β] [Finite α m] [i : IteratorLoop α m n] where
|
||||
lawful : i = .defaultImplementation
|
||||
|
||||
@@ -182,21 +184,23 @@ This is the loop implementation of the default instance `IteratorLoopPartial.def
|
||||
@[specialize]
|
||||
partial def IterM.DefaultConsumers.forInPartial {m : Type w → Type w'} {α : Type w} {β : Type w}
|
||||
[Iterator α m β]
|
||||
{n : Type x → Type x'} [Monad n]
|
||||
(lift : ∀ γ δ, (γ → n δ) → m γ → n δ) (γ : Type x)
|
||||
{n : Type w → Type w''} [Monad n]
|
||||
(lift : ∀ γ, m γ → n γ) (γ : Type w)
|
||||
(it : IterM (α := α) m β) (init : γ)
|
||||
(f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (ForInStep γ)) : n γ :=
|
||||
(lift _ _ · it.step) fun
|
||||
| .yield it' out h => do
|
||||
match ← f out (.direct ⟨_, h⟩) init with
|
||||
| .yield c =>
|
||||
IterM.DefaultConsumers.forInPartial lift _ it' c
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done c => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forInPartial lift _ it' init
|
||||
letI : MonadLift m n := ⟨fun {γ} => lift γ⟩
|
||||
do
|
||||
match ← it.step with
|
||||
| .yield it' out h =>
|
||||
match ← f out (.direct ⟨_, h⟩) init with
|
||||
| .yield c =>
|
||||
IterM.DefaultConsumers.forInPartial lift _ it' c
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init
|
||||
| .done c => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forInPartial lift _ it' init
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init
|
||||
|
||||
/--
|
||||
This is the default implementation of the `IteratorLoopPartial` class.
|
||||
@@ -205,11 +209,11 @@ implementations are possible and should be used instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IteratorLoopPartial.defaultImplementation {α : Type w} {m : Type w → Type w'}
|
||||
{n : Type x → Type x'} [Monad m] [Monad n] [Iterator α m β] :
|
||||
{n : Type w → Type w''} [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorLoopPartial α m n where
|
||||
forInPartial lift := IterM.DefaultConsumers.forInPartial lift _
|
||||
|
||||
instance (α : Type w) (m : Type w → Type w') (n : Type x → Type x')
|
||||
instance (α : Type w) (m : Type w → Type w') (n : Type w → Type w'')
|
||||
[Monad m] [Monad n] [Iterator α m β] [Finite α m] :
|
||||
letI : IteratorLoop α m n := .defaultImplementation
|
||||
LawfulIteratorLoop α m n :=
|
||||
@@ -217,7 +221,7 @@ instance (α : Type w) (m : Type w → Type w') (n : Type x → Type x')
|
||||
⟨rfl⟩
|
||||
|
||||
theorem IteratorLoop.wellFounded_of_finite {m : Type w → Type w'}
|
||||
{α β : Type w} {γ : Type x} [Iterator α m β] [Finite α m] :
|
||||
{α β γ : Type w} [Iterator α m β] [Finite α m] :
|
||||
WellFounded α m (γ := γ) fun _ _ _ => True := by
|
||||
apply Subrelation.wf
|
||||
(r := InvImage IterM.TerminationMeasures.Finite.Rel (fun p => p.1.finitelyManySteps))
|
||||
@@ -233,9 +237,9 @@ theorem IteratorLoop.wellFounded_of_finite {m : Type w → Type w'}
|
||||
This `ForIn'`-style loop construct traverses a finite iterator using an `IteratorLoop` instance.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IteratorLoop.finiteForIn' {m : Type w → Type w'} {n : Type x → Type x'}
|
||||
def IteratorLoop.finiteForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
(lift : ∀ γ δ, (γ → n δ) → m γ → n δ) :
|
||||
(lift : ∀ γ, m γ → n γ) :
|
||||
ForIn' n (IterM (α := α) m β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' {γ} [Monad n] it init f :=
|
||||
IteratorLoop.forIn (α := α) (m := m) lift γ (fun _ _ _ => True)
|
||||
@@ -249,30 +253,23 @@ or future library improvements will make it more comfortable.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n] [Monad n]
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
[MonadLiftT m n] :
|
||||
ForIn' n (IterM (α := α) m β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ :=
|
||||
IteratorLoop.finiteForIn' (fun _ _ f x => monadLift x >>= f)
|
||||
IteratorLoop.finiteForIn' (fun _ => monadLift)
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
[MonadLiftT m n] [Monad n] :
|
||||
[MonadLiftT m n] :
|
||||
ForIn n (IterM (α := α) m β) β :=
|
||||
haveI : ForIn' n (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
@[always_inline, inline]
|
||||
def IterM.Partial.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n] [MonadLiftT m n] [Monad n] :
|
||||
ForIn' n (IterM.Partial (α := α) m β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f := IteratorLoopPartial.forInPartial (α := α) (m := m) (n := n)
|
||||
(fun _ _ f x => monadLift x >>= f) it.it init f
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n] [MonadLiftT m n] [Monad n] :
|
||||
ForIn n (IterM.Partial (α := α) m β) β :=
|
||||
haveI : ForIn' n (IterM.Partial (α := α) m β) β _ := IterM.Partial.instForIn'
|
||||
instForInOfForIn'
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoopPartial α m n] [MonadLiftT m n] :
|
||||
ForIn' n (IterM.Partial (α := α) m β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f :=
|
||||
IteratorLoopPartial.forInPartial (α := α) (m := m) (fun _ => monadLift) it.it init f
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [Finite α m] [IteratorLoop α m n]
|
||||
|
||||
@@ -16,30 +16,30 @@ public section
|
||||
namespace Std.Iterators
|
||||
|
||||
theorem Iter.forIn'_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{m : Type w → Type w''} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f =
|
||||
IterM.DefaultConsumers.forIn' (fun _ _ f x => f x.run) γ (fun _ _ _ => True)
|
||||
IterM.DefaultConsumers.forIn' (fun _ c => pure c.run) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it.toIterM init _ (fun _ => id)
|
||||
(fun out h acc => (⟨·, .intro⟩) <$>
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{m : Type w → Type w''} [Monad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (b : β) → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f =
|
||||
IterM.DefaultConsumers.forIn' (fun _ _ f c => f c.run) γ (fun _ _ _ => True)
|
||||
IterM.DefaultConsumers.forIn' (fun _ c => pure c.run) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it.toIterM init _ (fun _ => id)
|
||||
(fun out _ acc => (⟨·, .intro⟩) <$>
|
||||
f out acc) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
@@ -48,7 +48,7 @@ theorem Iter.forIn'_eq_forIn'_toIterM {α β : Type w} [Iterator α Id β]
|
||||
letI : ForIn' m (IterM (α := α) Id β) β _ := IterM.instForIn'
|
||||
ForIn'.forIn' it.toIterM init
|
||||
(fun out h acc => f out (isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc) := by
|
||||
simp [ForIn'.forIn', Iter.instForIn', IterM.instForIn', monadLift]
|
||||
rfl
|
||||
|
||||
theorem Iter.forIn_eq_forIn_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
@@ -57,12 +57,12 @@ theorem Iter.forIn_eq_forIn_toIterM {α β : Type w} [Iterator α Id β]
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f =
|
||||
ForIn.forIn it.toIterM init f := by
|
||||
simp [forIn_eq_forIn', forIn'_eq_forIn'_toIterM, -forIn'_eq_forIn]
|
||||
rfl
|
||||
|
||||
theorem Iter.forIn'_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x''} [Monad m] [LawfulMonad m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f = (do
|
||||
@@ -77,27 +77,20 @@ theorem Iter.forIn'_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
ForIn'.forIn' it' init
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init) := by
|
||||
simp only [forIn'_eq]
|
||||
rw [IterM.DefaultConsumers.forIn'_eq_match_step]
|
||||
simp only [bind_map_left, Iter.step]
|
||||
cases it.toIterM.step.run using PlausibleIterStep.casesOn
|
||||
· simp only [IterM.Step.toPure_yield, PlausibleIterStep.yield, toIter_toIterM, toIterM_toIter]
|
||||
apply bind_congr
|
||||
rw [Iter.forIn'_eq_forIn'_toIterM, @IterM.forIn'_eq_match_step, Iter.step]
|
||||
simp only [liftM, monadLift, pure_bind]
|
||||
generalize it.toIterM.step = step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep
|
||||
· simp
|
||||
· simp only
|
||||
apply IterM.DefaultConsumers.forIn'_eq_forIn'
|
||||
intros; congr
|
||||
· simp only
|
||||
apply IterM.DefaultConsumers.forIn'_eq_forIn'
|
||||
intros; congr
|
||||
· simp
|
||||
rfl
|
||||
· rfl
|
||||
· rfl
|
||||
|
||||
theorem Iter.forIn_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f = (do
|
||||
match it.step with
|
||||
@@ -107,15 +100,23 @@ theorem Iter.forIn_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
| .done c => return c
|
||||
| .skip it' _ => ForIn.forIn it' init f
|
||||
| .done _ => return init) := by
|
||||
simp only [forIn_eq_forIn']
|
||||
exact forIn'_eq_match_step
|
||||
rw [Iter.forIn_eq_forIn_toIterM, @IterM.forIn_eq_match_step, Iter.step]
|
||||
simp only [liftM, monadLift, pure_bind]
|
||||
generalize it.toIterM.step = step
|
||||
cases step using PlausibleIterStep.casesOn
|
||||
· apply bind_congr
|
||||
intro forInStep
|
||||
rfl
|
||||
· rfl
|
||||
· rfl
|
||||
|
||||
private theorem Iter.forIn'_toList.aux {ρ : Type u} {α : Type v} {γ : Type x} {m : Type x → Type x'}
|
||||
private theorem Iter.forIn'_toList.aux {ρ : Type u} {α : Type v} {γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] {_ : Membership α ρ} [ForIn' m ρ α inferInstance]
|
||||
{r s : ρ} {init : γ} {f : (a : α) → _ → γ → m (ForInStep γ)} (h : r = s) :
|
||||
forIn' r init f = forIn' s init (fun a h' acc => f a (h ▸ h') acc) := by
|
||||
cases h; rfl
|
||||
|
||||
|
||||
theorem Iter.isPlausibleStep_iff_step_eq {α β} [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
@@ -184,11 +185,11 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
|
||||
simp [heq, IterStep.successor] at h₁
|
||||
|
||||
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it.toList init f = ForIn'.forIn' it init (fun out h acc => f out (Iter.mem_toList_iff_isPlausibleIndirectOutput.mpr h) acc) := by
|
||||
@@ -218,11 +219,11 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{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
|
||||
@@ -230,10 +231,10 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
congr
|
||||
|
||||
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toList init f = ForIn.forIn it init f := by
|
||||
rw [List.forIn_eq_foldlM]
|
||||
@@ -249,14 +250,14 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
cases forInStep
|
||||
· induction it'.toList <;> simp [*]
|
||||
· simp only [ForIn.forIn] at ihy
|
||||
simp [ihy h]
|
||||
simp [ihy h, forIn_eq_forIn_toIterM]
|
||||
· rename_i it' h
|
||||
simp only [bind_pure_comp]
|
||||
rw [ihs h]
|
||||
· simp
|
||||
|
||||
theorem Iter.foldM_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [IteratorLoop α Id m] {f : γ → β → m γ}
|
||||
theorem Iter.foldM_eq_forIn {α β γ : Type w} [Iterator α Id β] [Finite α Id] {m : Type w → Type w'}
|
||||
[Monad m] [IteratorLoop α Id m] {f : γ → β → m γ}
|
||||
{init : γ} {it : Iter (α := α) β} :
|
||||
it.foldM (init := init) f = ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x) :=
|
||||
(rfl)
|
||||
@@ -265,19 +266,19 @@ theorem Iter.foldM_eq_foldM_toIterM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ} {f : γ → β → m γ} :
|
||||
it.foldM (init := init) f = it.toIterM.foldM (init := init) f := by
|
||||
simp [foldM_eq_forIn, IterM.foldM_eq_forIn, forIn_eq_forIn_toIterM]
|
||||
it.foldM (init := init) f = it.toIterM.foldM (init := init) f :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.forIn_yield_eq_foldM {α β : Type w} {γ : Type x} {δ : Type x} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
theorem Iter.forIn_yield_eq_foldM {α β γ δ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] {f : β → γ → m δ} {g : β → γ → δ → γ} {init : γ}
|
||||
{it : Iter (α := α) β} :
|
||||
ForIn.forIn (m := m) it init (fun c b => (fun d => .yield (g c b d)) <$> f c b) =
|
||||
it.foldM (m := m) (fun b c => g c b <$> f c b) init := by
|
||||
ForIn.forIn it init (fun c b => (fun d => .yield (g c b d)) <$> f c b) =
|
||||
it.foldM (fun b c => g c b <$> f c b) init := by
|
||||
simp [Iter.foldM_eq_forIn]
|
||||
|
||||
theorem Iter.foldM_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
theorem Iter.foldM_eq_match_step {α β γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type w → Type w'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] {f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.foldM (init := init) f = (do
|
||||
match it.step with
|
||||
@@ -288,19 +289,20 @@ theorem Iter.foldM_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
|
||||
generalize it.step = step
|
||||
cases step using PlausibleIterStep.casesOn <;> simp [foldM_eq_forIn]
|
||||
|
||||
theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
theorem Iter.foldlM_toList {α β γ : Type w} [Iterator α Id β] [Finite α Id] {m : Type w → Type w'}
|
||||
[Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → m γ}
|
||||
{init : γ} {it : Iter (α := α) β} :
|
||||
it.toList.foldlM (init := init) f = it.foldM (init := init) f := by
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toList]
|
||||
simp only [List.forIn_yield_eq_foldlM, id_map']
|
||||
|
||||
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[Finite α Id] {m : Type w → Type w''} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{γ : Type w} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
forIn it init f = ForInStep.value <$>
|
||||
it.foldM (fun c b => match c with
|
||||
@@ -308,28 +310,31 @@ theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
|
||||
| .done c => pure (.done c)) (ForInStep.yield init) := by
|
||||
simp only [← Iter.forIn_toList, List.forIn_eq_foldlM, ← Iter.foldlM_toList]; rfl
|
||||
|
||||
theorem Iter.fold_eq_forIn {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
theorem Iter.fold_eq_forIn {α β γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] {f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f =
|
||||
(ForIn.forIn (m := Id) it init (fun x acc => pure (ForInStep.yield (f acc x)))).run := by
|
||||
rfl
|
||||
|
||||
theorem Iter.fold_eq_foldM {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] {f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
theorem Iter.fold_eq_foldM {α β γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] {f : γ → β → γ} {init : γ}
|
||||
{it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (it.foldM (m := Id) (init := init) (pure <| f · ·)).run := by
|
||||
simp [foldM_eq_forIn, fold_eq_forIn]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.forIn_pure_yield_eq_fold {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : β → γ → γ} {init : γ}
|
||||
theorem Iter.forIn_pure_yield_eq_fold {α β γ : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id]
|
||||
[LawfulIteratorLoop α Id Id] {f : β → γ → γ} {init : γ}
|
||||
{it : Iter (α := α) β} :
|
||||
ForIn.forIn (m := Id) it init (fun c b => pure (.yield (f c b))) =
|
||||
pure (it.fold (fun b c => f c b) init) := by
|
||||
simp only [fold_eq_forIn]
|
||||
rfl
|
||||
|
||||
theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id] {f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
theorem Iter.fold_eq_match_step {α β γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.fold (init := init) f = (match it.step with
|
||||
| .yield it' out _ => it'.fold (init := f init out) f
|
||||
| .skip it' _ => it'.fold (init := init) f
|
||||
@@ -340,7 +345,7 @@ theorem Iter.fold_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
|
||||
cases step using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
theorem Iter.foldl_toList {α β γ : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
|
||||
@@ -15,26 +15,28 @@ namespace Std.Iterators
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α m β]
|
||||
{n : Type x → Type x'} [Monad n]
|
||||
{lift : ∀ γ δ, (γ → n δ) → m γ → n δ} {γ : Type x}
|
||||
{n : Type w → Type w''} [Monad n]
|
||||
{lift : ∀ γ, m γ → n γ} {γ : Type w}
|
||||
{plausible_forInStep : β → γ → ForInStep γ → Prop}
|
||||
{wf : IteratorLoop.WellFounded α m plausible_forInStep}
|
||||
{it : IterM (α := α) m β} {init : γ}
|
||||
{P hP} {f : (b : β) → P b → (c : γ) → n (Subtype (plausible_forInStep b c))} :
|
||||
IterM.DefaultConsumers.forIn' lift γ plausible_forInStep wf it init P hP f =
|
||||
(lift _ _ · it.step) (fun
|
||||
| .yield it' out h => do
|
||||
match ← f out (hP _ <| .direct ⟨_, h⟩) init with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' c P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| ⟨.done c, _⟩ => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' init P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| .done _ => return init) := by
|
||||
{P hP}
|
||||
{f : (b : β) → P b → (c : γ) → n (Subtype (plausible_forInStep b c))} :
|
||||
IterM.DefaultConsumers.forIn' lift γ plausible_forInStep wf it init P hP f = (do
|
||||
match ← lift _ it.step with
|
||||
| .yield it' out h =>
|
||||
match ← f out (hP _ <| .direct ⟨_, h⟩) init with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' c P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| ⟨.done c, _⟩ => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' init P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| .done _ => return init) := by
|
||||
rw [forIn']
|
||||
congr; ext step
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step using PlausibleIterStep.casesOn <;> rfl
|
||||
|
||||
theorem IterM.forIn'_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
@@ -42,8 +44,7 @@ theorem IterM.forIn'_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
[MonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → n (ForInStep γ)} :
|
||||
letI : ForIn' n (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
ForIn'.forIn' it init f = IterM.DefaultConsumers.forIn' (n := n)
|
||||
(fun _ _ f x => monadLift x >>= f) γ (fun _ _ _ => True)
|
||||
ForIn'.forIn' it init f = IterM.DefaultConsumers.forIn' (fun _ => monadLift) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) ((⟨·, .intro⟩) <$> f · · ·) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
@@ -51,15 +52,14 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
{n : Type w → Type w''} [Monad n] [IteratorLoop α m n] [hl : LawfulIteratorLoop α m n]
|
||||
[MonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : β → γ → n (ForInStep γ)} :
|
||||
ForIn.forIn it init f = IterM.DefaultConsumers.forIn' (n := n)
|
||||
(fun _ _ f x => monadLift x >>= f) γ (fun _ _ _ => True)
|
||||
ForIn.forIn it init f = IterM.DefaultConsumers.forIn' (fun _ => monadLift) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) (fun out _ acc => (⟨·, .intro⟩) <$> f out acc) := by
|
||||
cases hl.lawful; rfl
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_forIn' {m : Type w → Type w'} {α : Type w} {β : Type w}
|
||||
[Iterator α m β]
|
||||
{n : Type x → Type x'} [Monad n]
|
||||
{liftBind : ∀ γ δ, (γ → n δ) → m γ → n δ} {γ : Type x}
|
||||
{n : Type w → Type w''} [Monad n]
|
||||
{lift : ∀ γ, m γ → n γ} {γ : Type w}
|
||||
{Pl : β → γ → ForInStep γ → Prop}
|
||||
{wf : IteratorLoop.WellFounded α m Pl}
|
||||
{it : IterM (α := α) m β} {init : γ}
|
||||
@@ -68,10 +68,11 @@ theorem IterM.DefaultConsumers.forIn'_eq_forIn' {m : Type w → Type w'} {α : T
|
||||
{f : (b : β) → P b → (c : γ) → n (Subtype (Pl b c))}
|
||||
{g : (b : β) → Q b → (c : γ) → n (Subtype (Pl b c))}
|
||||
(hfg : ∀ b c, (hPb : P b) → (hQb : Q b) → f b hPb c = g b hQb c) :
|
||||
IterM.DefaultConsumers.forIn' liftBind γ Pl wf it init P hP f =
|
||||
IterM.DefaultConsumers.forIn' liftBind γ Pl wf it init Q hQ g := by
|
||||
IterM.DefaultConsumers.forIn' lift γ Pl wf it init P hP f =
|
||||
IterM.DefaultConsumers.forIn' lift γ Pl wf it init Q hQ g := by
|
||||
rw [forIn', forIn']
|
||||
congr; ext step
|
||||
apply bind_congr
|
||||
intro step
|
||||
split
|
||||
· congr
|
||||
· apply hfg
|
||||
@@ -137,7 +138,8 @@ theorem IterM.forIn_eq_match_step {α β : Type w} {m : Type w → Type w'} [Ite
|
||||
| .skip it' _ => ForIn.forIn it' init f
|
||||
| .done _ => return init) := by
|
||||
simp only [forIn]
|
||||
exact forIn'_eq_match_step
|
||||
rw [forIn'_eq_match_step]
|
||||
rfl
|
||||
|
||||
theorem IterM.forM_eq_forIn {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad n] [LawfulMonad n]
|
||||
|
||||
@@ -130,7 +130,7 @@ Safer alternatives include:
|
||||
* `List.head?`, which returns an `Option`, and
|
||||
* `List.headD`, which returns an explicitly-provided fallback value on empty lists.
|
||||
-/
|
||||
@[expose] def head! [Inhabited α] : List α → α
|
||||
def head! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
| a::_ => a
|
||||
|
||||
@@ -362,13 +362,12 @@ theorem not_lex_antisymm [DecidableEq α] {r : α → α → Prop} [DecidableRel
|
||||
· exact h₁ (Lex.rel hba)
|
||||
· exact eq (antisymm _ _ hab hba)
|
||||
|
||||
protected theorem le_antisymm [LT α]
|
||||
protected theorem le_antisymm [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{as bs : List α} (h₁ : as ≤ bs) (h₂ : bs ≤ as) : as = bs :=
|
||||
open Classical in
|
||||
not_lex_antisymm i.antisymm h₁ h₂
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[s : Std.Antisymm (¬ · < · : α → α → Prop)] :
|
||||
Std.Antisymm (· ≤ · : List α → List α → Prop) where
|
||||
antisymm _ _ h₁ h₂ := List.le_antisymm h₁ h₂
|
||||
|
||||
@@ -22,9 +22,9 @@ namespace List
|
||||
@[simp] theorem not_lex_lt [LT α] {l₁ l₂ : List α} : ¬ Lex (· < ·) l₁ l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
|
||||
protected theorem not_lt_iff_ge [LT α] {l₁ l₂ : List α} : ¬ l₁ < l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
protected theorem not_le_iff_gt [LT α] {l₁ l₂ : List α} :
|
||||
protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : List α} :
|
||||
¬ l₁ ≤ l₂ ↔ l₂ < l₁ :=
|
||||
Classical.not_not
|
||||
Decidable.not_not
|
||||
|
||||
theorem lex_irrefl {r : α → α → Prop} (irrefl : ∀ x, ¬r x x) (l : List α) : ¬Lex r l l := by
|
||||
induction l with
|
||||
@@ -78,14 +78,13 @@ theorem not_cons_lex_cons_iff [DecidableEq α] [DecidableRel r] {a b} {l₁ l₂
|
||||
¬ Lex r (a :: l₁) (b :: l₂) ↔ (¬ r a b ∧ a ≠ b) ∨ (¬ r a b ∧ ¬ Lex r l₁ l₂) := by
|
||||
rw [cons_lex_cons_iff, not_or, Decidable.not_and_iff_or_not, and_or_left]
|
||||
|
||||
theorem cons_le_cons_iff [LT α]
|
||||
theorem cons_le_cons_iff [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{a b} {l₁ l₂ : List α} :
|
||||
(a :: l₁) ≤ (b :: l₂) ↔ a < b ∨ a = b ∧ l₁ ≤ l₂ := by
|
||||
dsimp only [instLE, instLT, List.le, List.lt]
|
||||
open Classical in
|
||||
simp only [not_cons_lex_cons_iff, ne_eq]
|
||||
constructor
|
||||
· rintro (⟨h₁, h₂⟩ | ⟨h₁, h₂⟩)
|
||||
@@ -105,7 +104,7 @@ theorem cons_le_cons_iff [LT α]
|
||||
· right
|
||||
exact ⟨fun w => i₀.irrefl _ (h₁ ▸ w), h₂⟩
|
||||
|
||||
theorem not_lt_of_cons_le_cons [LT α]
|
||||
theorem not_lt_of_cons_le_cons [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -115,7 +114,7 @@ theorem not_lt_of_cons_le_cons [LT α]
|
||||
· exact i₁.asymm _ _ h
|
||||
· exact i₀.irrefl _
|
||||
|
||||
theorem le_of_cons_le_cons [LT α]
|
||||
theorem le_of_cons_le_cons [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -166,7 +165,7 @@ instance [LT α] [Trans (· < · : α → α → Prop) (· < ·) (· < ·)] :
|
||||
@[deprecated List.le_antisymm (since := "2024-12-13")]
|
||||
protected abbrev lt_antisymm := @List.le_antisymm
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α]
|
||||
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -181,7 +180,7 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
| cons c l₁ =>
|
||||
apply Lex.rel
|
||||
replace h₁ := not_lt_of_cons_le_cons h₁
|
||||
apply Classical.byContradiction
|
||||
apply Decidable.byContradiction
|
||||
intro h₂
|
||||
have := i₃.trans h₁ h₂
|
||||
contradiction
|
||||
@@ -194,9 +193,9 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
by_cases w₅ : a = c
|
||||
· subst w₅
|
||||
exact Lex.cons (ih (le_of_cons_le_cons h₁))
|
||||
· exact Lex.rel (Classical.byContradiction fun w₆ => w₅ (i₂.antisymm _ _ w₄ w₆))
|
||||
· exact Lex.rel (Decidable.byContradiction fun w₆ => w₅ (i₂.antisymm _ _ w₄ w₆))
|
||||
|
||||
protected theorem le_trans [LT α]
|
||||
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -204,7 +203,7 @@ protected theorem le_trans [LT α]
|
||||
{l₁ l₂ l₃ : List α} (h₁ : l₁ ≤ l₂) (h₂ : l₂ ≤ l₃) : l₁ ≤ l₃ :=
|
||||
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -232,9 +231,9 @@ instance [LT α] [Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Asymm (· < · : List α → List α → Prop) where
|
||||
asymm _ _ := List.lt_asymm
|
||||
|
||||
theorem not_lex_total {r : α → α → Prop}
|
||||
theorem not_lex_total [DecidableEq α] {r : α → α → Prop} [DecidableRel r]
|
||||
(h : ∀ x y : α, ¬ r x y ∨ ¬ r y x) (l₁ l₂ : List α) : ¬ Lex r l₁ l₂ ∨ ¬ Lex r l₂ l₁ := by
|
||||
rw [Classical.or_iff_not_imp_left, Classical.not_not]
|
||||
rw [Decidable.or_iff_not_imp_left, Decidable.not_not]
|
||||
intro w₁ w₂
|
||||
match l₁, l₂, w₁, w₂ with
|
||||
| nil, _ :: _, .nil, w₂ => simp at w₂
|
||||
@@ -247,11 +246,11 @@ theorem not_lex_total {r : α → α → Prop}
|
||||
| _ :: l₁, _ :: l₂, .cons _, .cons _ =>
|
||||
obtain (_ | _) := not_lex_total h l₁ l₂ <;> contradiction
|
||||
|
||||
protected theorem le_total [LT α]
|
||||
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] (l₁ l₂ : List α) : l₁ ≤ l₂ ∨ l₂ ≤ l₁ :=
|
||||
not_lex_total i.total l₂ l₁
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : List α → List α → Prop) where
|
||||
total := List.le_total
|
||||
@@ -259,10 +258,10 @@ instance [LT α]
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
{l₁ l₂ : List α} : ¬ l₁ < l₂ ↔ l₂ ≤ l₁ := Iff.rfl
|
||||
|
||||
@[simp] protected theorem not_le [LT α]
|
||||
{l₁ l₂ : List α} : ¬ l₂ ≤ l₁ ↔ l₁ < l₂ := Classical.not_not
|
||||
@[simp] protected theorem not_le [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{l₁ l₂ : List α} : ¬ l₂ ≤ l₁ ↔ l₁ < l₂ := Decidable.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
protected theorem le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)]
|
||||
{l₁ l₂ : List α} (h : l₁ < l₂) : l₁ ≤ l₂ := by
|
||||
obtain (h' | h') := List.le_total l₁ l₂
|
||||
@@ -270,7 +269,7 @@ protected theorem le_of_lt [LT α]
|
||||
· exfalso
|
||||
exact h' h
|
||||
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Total (¬ · < · : α → α → Prop)]
|
||||
@@ -281,7 +280,7 @@ protected theorem le_iff_lt_or_eq [LT α]
|
||||
· right
|
||||
apply List.le_antisymm h h'
|
||||
· left
|
||||
exact Classical.not_not.mp h'
|
||||
exact Decidable.not_not.mp h'
|
||||
· rintro (h | rfl)
|
||||
· exact List.le_of_lt h
|
||||
· exact List.le_refl l₁
|
||||
@@ -446,17 +445,16 @@ theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α → α
|
||||
simpa using w₁ (j + 1) (by simpa)
|
||||
· simpa using w₂
|
||||
|
||||
protected theorem lt_iff_exists [LT α] {l₁ l₂ : List α} :
|
||||
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {l₁ l₂ : List α} :
|
||||
l₁ < l₂ ↔
|
||||
(l₁ = l₂.take l₁.length ∧ l₁.length < l₂.length) ∨
|
||||
(∃ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) ∧ l₁[i] < l₂[i]) := by
|
||||
open Classical in
|
||||
rw [← lex_eq_true_iff_lt, lex_eq_true_iff_exists]
|
||||
simp
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
protected theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {l₁ l₂ : List α} :
|
||||
@@ -465,7 +463,6 @@ protected theorem le_iff_exists [LT α]
|
||||
(∃ (i : Nat) (h₁ : i < l₁.length) (h₂ : i < l₂.length),
|
||||
(∀ j, (hj : j < i) →
|
||||
l₁[j]'(Nat.lt_trans hj h₁) = l₂[j]'(Nat.lt_trans hj h₂)) ∧ l₁[i] < l₂[i]) := by
|
||||
open Classical in
|
||||
rw [← lex_eq_false_iff_ge, lex_eq_false_iff_exists]
|
||||
· simp only [isEqv_eq, beq_iff_eq, decide_eq_true_eq]
|
||||
simp only [eq_comm]
|
||||
@@ -480,7 +477,7 @@ theorem append_left_lt [LT α] {l₁ l₂ l₃ : List α} (h : l₂ < l₃) :
|
||||
| nil => simp [h]
|
||||
| cons a l₁ ih => simp [cons_lt_cons_iff, ih]
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
theorem append_left_le [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -514,7 +511,7 @@ protected theorem map_lt [LT α] [LT β]
|
||||
| cons a l₁, cons b l₂, .rel h =>
|
||||
simp [cons_lt_cons_iff, w, h]
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq β] [LT β] [DecidableLT β]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
|
||||
@@ -258,55 +258,6 @@ instance (r : α → β → Prop) [s : DecidableRel r] : DecidableRel (Option.lt
|
||||
| some _, none => isFalse not_false
|
||||
| none, none => isFalse not_false
|
||||
|
||||
namespace SomeLtNone
|
||||
|
||||
/--
|
||||
Lifts an ordering relation to `Option` such that `none` is the *greatest* element.
|
||||
|
||||
It can be understood as adding a distinguished greatest element, represented by `none`, to both `α`
|
||||
and `β`.
|
||||
|
||||
Caution: Given `LT α`, `Option.SomeLtNone.lt LT.lt` differs from the `LT (Option α)` instance,
|
||||
which is implemented by `Option.lt Lt.lt`.
|
||||
|
||||
Examples:
|
||||
* `Option.lt (fun n k : Nat => n < k) none none = False`
|
||||
* `Option.lt (fun n k : Nat => n < k) none (some 3) = False`
|
||||
* `Option.lt (fun n k : Nat => n < k) (some 3) none = True`
|
||||
* `Option.lt (fun n k : Nat => n < k) (some 4) (some 5) = True`
|
||||
* `Option.le (fun n k : Nat => n < k) (some 5) (some 4) = False`
|
||||
* `Option.lt (fun n k : Nat => n < k) (some 4) (some 4) = False`
|
||||
-/
|
||||
def lt {α} (r : α → β → Prop) : Option α → Option β → Prop
|
||||
| none, _ => False
|
||||
| some _, none => True
|
||||
| some x, some y => r x y
|
||||
|
||||
/--
|
||||
Lifts an ordering relation to `Option` such that `none` is the *greatest* element.
|
||||
|
||||
It can be understood as adding a distinguished greatest element, represented by `none`, to both `α`
|
||||
and `β`.
|
||||
|
||||
Caution: Given `LE α`, `Option.SomeLtNone.le LE.le` differs from the `LE (Option α)` instance,
|
||||
which is implemented by `Option.le LE.le`.
|
||||
|
||||
Examples:
|
||||
* `Option.le (fun n k : Nat => n < k) none none = True`
|
||||
* `Option.le (fun n k : Nat => n < k) none (some 3) = False`
|
||||
* `Option.le (fun n k : Nat => n < k) (some 3) none = True`
|
||||
* `Option.le (fun n k : Nat => n < k) (some 4) (some 5) = True`
|
||||
* `Option.le (fun n k : Nat => n < k) (some 5) (some 4) = False`
|
||||
* `Option.le (fun n k : Nat => n < k) (some 4) (some 4) = True`
|
||||
-/
|
||||
def le {α} (r : α → β → Prop) : Option α → Option β → Prop
|
||||
| none, none => True
|
||||
| none, some _ => False
|
||||
| some _, none => True
|
||||
| some x, some y => r x y
|
||||
|
||||
end SomeLtNone
|
||||
|
||||
/--
|
||||
Applies a function to a two optional values if both are present. Otherwise, if one value is present,
|
||||
it is returned and the function is not used.
|
||||
|
||||
@@ -1922,38 +1922,4 @@ theorem map_min [Min α] [Min β] {o o' : Option α} {f : α → β} (hf : ∀ x
|
||||
(min o o').map f = min (o.map f) (o'.map f) := by
|
||||
cases o <;> cases o' <;> simp [*]
|
||||
|
||||
theorem wellFounded_lt {α} {rel : α → α → Prop} (h : WellFounded rel) :
|
||||
WellFounded (Option.lt rel) := by
|
||||
refine ⟨fun x => ?_⟩
|
||||
have hn : Acc (Option.lt rel) none := by
|
||||
refine Acc.intro none ?_
|
||||
intro y hyx
|
||||
cases y <;> cases hyx
|
||||
cases x
|
||||
· exact hn
|
||||
· rename_i x
|
||||
induction h.apply x
|
||||
rename_i _ _ ih
|
||||
refine Acc.intro _ (fun y hy => ?_)
|
||||
cases y
|
||||
· exact hn
|
||||
· exact ih _ hy
|
||||
|
||||
theorem SomeLtNone.wellFounded_lt {α} {r : α → α → Prop} (h : WellFounded r) :
|
||||
WellFounded (SomeLtNone.lt r) := by
|
||||
refine ⟨?_⟩
|
||||
intro x
|
||||
constructor
|
||||
intro x' hlt
|
||||
match x' with
|
||||
| none => contradiction
|
||||
| some x' =>
|
||||
clear hlt
|
||||
induction h.apply x'
|
||||
rename_i ih
|
||||
refine Acc.intro _ (fun x'' hlt' => ?_)
|
||||
match x'' with
|
||||
| none => contradiction
|
||||
| some x'' => exact ih x'' hlt'
|
||||
|
||||
end Option
|
||||
|
||||
@@ -247,12 +247,12 @@ theorem isEq_eq_beq_eq : ∀ {o : Ordering}, o.isEq = (o == .eq) := by decide
|
||||
theorem isNe_eq_not_beq_eq : ∀ {o : Ordering}, o.isNe = (!o == .eq) := by decide
|
||||
theorem isNe_eq_isLT_or_isGT : ∀ {o : Ordering}, o.isNe = (o.isLT || o.isGT) := by decide
|
||||
|
||||
@[simp] theorem not_isLT_eq_isGE : ∀ {o : Ordering}, (!o.isLT) = o.isGE := by decide
|
||||
@[simp] theorem not_isLE_eq_isGT : ∀ {o : Ordering}, (!o.isLE) = o.isGT := by decide
|
||||
@[simp] theorem not_isGT_eq_isLE : ∀ {o : Ordering}, (!o.isGT) = o.isLE := by decide
|
||||
@[simp] theorem not_isGE_eq_isLT : ∀ {o : Ordering}, (!o.isGE) = o.isLT := by decide
|
||||
@[simp] theorem not_isNe_eq_isEq : ∀ {o : Ordering}, (!o.isNe) = o.isEq := by decide
|
||||
theorem not_isEq_eq_isNe : ∀ {o : Ordering}, (!o.isEq) = o.isNe := by decide
|
||||
@[simp] theorem not_isLT_eq_isGE : ∀ {o : Ordering}, !o.isLT = o.isGE := by decide
|
||||
@[simp] theorem not_isLE_eq_isGT : ∀ {o : Ordering}, !o.isLE = o.isGT := by decide
|
||||
@[simp] theorem not_isGT_eq_isLE : ∀ {o : Ordering}, !o.isGT = o.isLE := by decide
|
||||
@[simp] theorem not_isGE_eq_isLT : ∀ {o : Ordering}, !o.isGE = o.isLT := by decide
|
||||
@[simp] theorem not_isNe_eq_isEq : ∀ {o : Ordering}, !o.isNe = o.isEq := by decide
|
||||
theorem not_isEq_eq_isNe : ∀ {o : Ordering}, !o.isEq = o.isNe := by decide
|
||||
|
||||
theorem ne_lt_iff_isGE : ∀ {o : Ordering}, ¬o = .lt ↔ o.isGE := by decide
|
||||
theorem ne_gt_iff_isLE : ∀ {o : Ordering}, ¬o = .gt ↔ o.isLE := by decide
|
||||
@@ -303,7 +303,7 @@ In particular, if `x < y` then the result is `Ordering.lt`. If `x = y` then the
|
||||
|
||||
`compareOfLessAndBEq` uses `BEq` instead of `DecidableEq`.
|
||||
-/
|
||||
@[inline, expose] def compareOfLessAndEq {α} (x y : α) [LT α] [Decidable (x < y)] [DecidableEq α] : Ordering :=
|
||||
@[inline] def compareOfLessAndEq {α} (x y : α) [LT α] [Decidable (x < y)] [DecidableEq α] : Ordering :=
|
||||
if x < y then Ordering.lt
|
||||
else if x = y then Ordering.eq
|
||||
else Ordering.gt
|
||||
@@ -329,7 +329,7 @@ by `cmp₂` to break the tie.
|
||||
|
||||
To lexicographically combine two `Ordering`s, use `Ordering.then`.
|
||||
-/
|
||||
@[inline, expose] def compareLex (cmp₁ cmp₂ : α → β → Ordering) (a : α) (b : β) : Ordering :=
|
||||
@[inline] def compareLex (cmp₁ cmp₂ : α → β → Ordering) (a : α) (b : β) : Ordering :=
|
||||
(cmp₁ a b).then (cmp₂ a b)
|
||||
|
||||
section Lemmas
|
||||
@@ -457,7 +457,7 @@ Examples:
|
||||
* `compareOn (· % 3) 5 6 = .gt`
|
||||
* `compareOn (·.foldl max 0) [1, 2, 3] [3, 2, 1] = .eq`
|
||||
-/
|
||||
@[inline, expose] def compareOn [ord : Ord β] (f : α → β) (x y : α) : Ordering :=
|
||||
@[inline] def compareOn [ord : Ord β] (f : α → β) (x y : α) : Ordering :=
|
||||
compare (f x) (f y)
|
||||
|
||||
instance : Ord Nat where
|
||||
@@ -724,7 +724,7 @@ protected theorem compare_eq_compare_toList {α n} [Ord α] {a b : Vector α n}
|
||||
end Vector
|
||||
|
||||
/-- The lexicographic order on pairs. -/
|
||||
@[expose] def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
def lexOrd [Ord α] [Ord β] : Ord (α × β) where
|
||||
compare := compareLex (compareOn (·.1)) (compareOn (·.2))
|
||||
|
||||
/--
|
||||
@@ -781,7 +781,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] protected def opposite (ord : Ord α) : Ord α where
|
||||
protected def opposite (ord : Ord α) : Ord α where
|
||||
compare x y := ord.compare y x
|
||||
|
||||
/--
|
||||
@@ -792,13 +792,13 @@ 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] protected def on (_ : Ord β) (f : α → β) : Ord α where
|
||||
protected def on (_ : Ord β) (f : α → β) : Ord α where
|
||||
compare := compareOn f
|
||||
|
||||
/--
|
||||
Constructs the lexicographic order on products `α × β` from orders for `α` and `β`.
|
||||
-/
|
||||
@[expose] protected abbrev lex (_ : Ord α) (_ : Ord β) : Ord (α × β) :=
|
||||
protected abbrev lex (_ : Ord α) (_ : Ord β) : Ord (α × β) :=
|
||||
lexOrd
|
||||
|
||||
/--
|
||||
@@ -811,7 +811,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] protected def lex' (ord₁ ord₂ : Ord α) : Ord α where
|
||||
protected def lex' (ord₁ ord₂ : Ord α) : Ord α where
|
||||
compare := compareLex ord₁.compare ord₂.compare
|
||||
|
||||
end Ord
|
||||
|
||||
@@ -111,20 +111,20 @@ theorem RangeIterator.step_eq_step {su} [UpwardEnumerable α] [SupportsUpperBoun
|
||||
simp [Iter.step, step_eq_monadicStep, Monadic.step_eq_step, IterM.Step.toPure]
|
||||
|
||||
@[always_inline, inline]
|
||||
instance RangeIterator.instIteratorLoop {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
{n : Type v → Type w} [Monad n] :
|
||||
instance RepeatIterator.instIteratorLoop {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
{n : Type u → Type w} [Monad n] :
|
||||
IteratorLoop (RangeIterator su α) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance RangeIterator.instIteratorLoopPartial {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
{n : Type v → Type w} [Monad n] : IteratorLoopPartial (RangeIterator su α) Id n :=
|
||||
instance RepeatIterator.instIteratorLoopPartial {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
{n : Type u → Type w} [Monad n] : IteratorLoopPartial (RangeIterator su α) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance RangeIterator.instIteratorCollect {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
instance RepeatIterator.instIteratorCollect {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
{n : Type u → Type w} [Monad n] : IteratorCollect (RangeIterator su α) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance RangeIterator.instIteratorCollectPartial {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
instance RepeatIterator.instIteratorCollectPartial {su} [UpwardEnumerable α] [SupportsUpperBound su α]
|
||||
{n : Type u → Type w} [Monad n] : IteratorCollectPartial (RangeIterator su α) Id n :=
|
||||
.defaultImplementation
|
||||
|
||||
|
||||
@@ -1213,7 +1213,7 @@ theorem contains_iff [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
instance [BEq α] [LawfulBEq α] (a : α) (as : Vector α n) : Decidable (a ∈ as) :=
|
||||
decidable_of_decidable_of_iff contains_iff
|
||||
|
||||
@[grind] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := by simp
|
||||
@[grind] theorem contains_empty [BEq α] : (#v[] : Vector α 0).contains a = false := rfl
|
||||
|
||||
@[simp, grind] theorem contains_eq_mem [BEq α] [LawfulBEq α] {a : α} {as : Vector α n} :
|
||||
as.contains a = decide (a ∈ as) := by
|
||||
@@ -2975,7 +2975,7 @@ variable [BEq α]
|
||||
rcases xs with ⟨xs, rfl⟩
|
||||
simp
|
||||
|
||||
@[simp, grind] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by simp
|
||||
@[simp, grind] theorem replace_empty : (#v[] : Vector α 0).replace a b = #v[] := by rfl
|
||||
|
||||
@[grind] theorem replace_singleton {a b c : α} : #v[a].replace b c = #v[if a == b then c else a] := by
|
||||
simp
|
||||
|
||||
@@ -28,9 +28,9 @@ namespace Vector
|
||||
@[simp] theorem le_toList [LT α] {xs ys : Vector α n} : xs.toList ≤ ys.toList ↔ xs ≤ ys := Iff.rfl
|
||||
|
||||
protected theorem not_lt_iff_ge [LT α] {xs ys : Vector α n} : ¬ xs < ys ↔ ys ≤ xs := Iff.rfl
|
||||
protected theorem not_le_iff_gt [LT α] {xs ys : Vector α n} :
|
||||
protected theorem not_le_iff_gt [DecidableEq α] [LT α] [DecidableLT α] {xs ys : Vector α n} :
|
||||
¬ xs ≤ ys ↔ ys < xs :=
|
||||
Classical.not_not
|
||||
Decidable.not_not
|
||||
|
||||
@[simp] theorem mk_lt_mk [LT α] :
|
||||
Vector.mk (α := α) (n := n) data₁ size₁ < Vector.mk data₂ size₂ ↔ data₁ < data₂ := Iff.rfl
|
||||
@@ -92,7 +92,7 @@ instance [LT α]
|
||||
Trans (· < · : Vector α n → Vector α n → Prop) (· < ·) (· < ·) where
|
||||
trans h₁ h₂ := Vector.lt_trans h₁ h₂
|
||||
|
||||
protected theorem lt_of_le_of_lt [LT α]
|
||||
protected theorem lt_of_le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i₀ : Std.Irrefl (· < · : α → α → Prop)]
|
||||
[i₁ : Std.Asymm (· < · : α → α → Prop)]
|
||||
[i₂ : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -100,7 +100,7 @@ protected theorem lt_of_le_of_lt [LT α]
|
||||
{xs ys zs : Vector α n} (h₁ : xs ≤ ys) (h₂ : ys < zs) : xs < zs :=
|
||||
Array.lt_of_le_of_lt h₁ h₂
|
||||
|
||||
protected theorem le_trans [LT α]
|
||||
protected theorem le_trans [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -108,7 +108,7 @@ protected theorem le_trans [LT α]
|
||||
{xs ys zs : Vector α n} (h₁ : xs ≤ ys) (h₂ : ys ≤ zs) : xs ≤ zs :=
|
||||
fun h₃ => h₁ (Vector.lt_of_le_of_lt h₂ h₃)
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -120,16 +120,16 @@ protected theorem lt_asymm [LT α]
|
||||
[i : Std.Asymm (· < · : α → α → Prop)]
|
||||
{xs ys : Vector α n} (h : xs < ys) : ¬ ys < xs := Array.lt_asymm h
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Asymm (· < · : α → α → Prop)] :
|
||||
Std.Asymm (· < · : Vector α n → Vector α n → Prop) where
|
||||
asymm _ _ := Vector.lt_asymm
|
||||
|
||||
protected theorem le_total [LT α]
|
||||
protected theorem le_total [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)] (xs ys : Vector α n) : xs ≤ ys ∨ ys ≤ xs :=
|
||||
Array.le_total _ _
|
||||
|
||||
instance [LT α]
|
||||
instance [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Total (¬ · < · : α → α → Prop)] :
|
||||
Std.Total (· ≤ · : Vector α n → Vector α n → Prop) where
|
||||
total := Vector.le_total
|
||||
@@ -137,15 +137,15 @@ instance [LT α]
|
||||
@[simp] protected theorem not_lt [LT α]
|
||||
{xs ys : Vector α n} : ¬ xs < ys ↔ ys ≤ xs := Iff.rfl
|
||||
|
||||
@[simp] protected theorem not_le [LT α]
|
||||
{xs ys : Vector α n} : ¬ ys ≤ xs ↔ xs < ys := Classical.not_not
|
||||
@[simp] protected theorem not_le [DecidableEq α] [LT α] [DecidableLT α]
|
||||
{xs ys : Vector α n} : ¬ ys ≤ xs ↔ xs < ys := Decidable.not_not
|
||||
|
||||
protected theorem le_of_lt [LT α]
|
||||
protected theorem le_of_lt [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[i : Std.Total (¬ · < · : α → α → Prop)]
|
||||
{xs ys : Vector α n} (h : xs < ys) : xs ≤ ys :=
|
||||
Array.le_of_lt h
|
||||
|
||||
protected theorem le_iff_lt_or_eq [LT α]
|
||||
protected theorem le_iff_lt_or_eq [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
[Std.Total (¬ · < · : α → α → Prop)]
|
||||
@@ -210,14 +210,14 @@ theorem lex_eq_false_iff_exists [BEq α] [PartialEquivBEq α] (lt : α → α
|
||||
rcases ys with ⟨ys, n₂⟩
|
||||
simp_all [Array.lex_eq_false_iff_exists]
|
||||
|
||||
protected theorem lt_iff_exists [LT α] {xs ys : Vector α n} :
|
||||
protected theorem lt_iff_exists [DecidableEq α] [LT α] [DecidableLT α] {xs ys : Vector α n} :
|
||||
xs < ys ↔
|
||||
(∃ (i : Nat) (h : i < n), (∀ j, (hj : j < i) → xs[j] = ys[j]) ∧ xs[i] < ys[i]) := by
|
||||
cases xs
|
||||
cases ys
|
||||
simp_all [Array.lt_iff_exists]
|
||||
|
||||
protected theorem le_iff_exists [LT α]
|
||||
protected theorem le_iff_exists [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)] {xs ys : Vector α n} :
|
||||
@@ -232,7 +232,7 @@ theorem append_left_lt [LT α] {xs : Vector α n} {ys ys' : Vector α m} (h : ys
|
||||
xs ++ ys < xs ++ ys' := by
|
||||
simpa using Array.append_left_lt h
|
||||
|
||||
theorem append_left_le [LT α]
|
||||
theorem append_left_le [DecidableEq α] [LT α] [DecidableLT α]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
@@ -245,7 +245,7 @@ protected theorem map_lt [LT α] [LT β]
|
||||
map f xs < map f ys := by
|
||||
simpa using Array.map_lt w h
|
||||
|
||||
protected theorem map_le [LT α] [LT β]
|
||||
protected theorem map_le [DecidableEq α] [LT α] [DecidableLT α] [DecidableEq β] [LT β] [DecidableLT β]
|
||||
[Std.Irrefl (· < · : α → α → Prop)]
|
||||
[Std.Asymm (· < · : α → α → Prop)]
|
||||
[Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
|
||||
@@ -11,5 +11,5 @@ public import Init.Grind.Tactics
|
||||
|
||||
public section
|
||||
|
||||
attribute [grind cases eager] And False Empty True PUnit Exists Subtype Prod PProd MProd
|
||||
attribute [grind cases eager] And Prod False Empty True PUnit Exists Subtype
|
||||
attribute [grind cases] Or
|
||||
|
||||
@@ -20,24 +20,6 @@ class AddRightCancel (M : Type u) [Add M] where
|
||||
/-- Addition is right-cancellative. -/
|
||||
add_right_cancel : ∀ a b c : M, a + c = b + c → a = b
|
||||
|
||||
class AddCommMonoid (M : Type u) extends Zero M, Add M where
|
||||
/-- Zero is the right identity for addition. -/
|
||||
add_zero : ∀ a : M, a + 0 = a
|
||||
/-- Addition is commutative. -/
|
||||
add_comm : ∀ a b : M, a + b = b + a
|
||||
/-- Addition is associative. -/
|
||||
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
|
||||
|
||||
attribute [instance 100] AddCommMonoid.toZero AddCommMonoid.toAdd
|
||||
|
||||
class AddCommGroup (M : Type u) extends AddCommMonoid M, Neg M, Sub M where
|
||||
/-- Negation is the left inverse of addition. -/
|
||||
neg_add_cancel : ∀ a : M, -a + a = 0
|
||||
/-- Subtraction is addition of the negative. -/
|
||||
sub_eq_add_neg : ∀ a b : M, a - b = a + -b
|
||||
|
||||
attribute [instance 100] AddCommGroup.toAddCommMonoid AddCommGroup.toNeg AddCommGroup.toSub
|
||||
|
||||
/--
|
||||
A module over the natural numbers, i.e. a type with zero, addition, and scalar multiplication by natural numbers,
|
||||
satisfying appropriate compatibilities.
|
||||
@@ -46,21 +28,25 @@ Equivalently, an additive commutative monoid.
|
||||
|
||||
Use `IntModule` if the type has negation.
|
||||
-/
|
||||
class NatModule (M : Type u) extends AddCommMonoid M where
|
||||
/-- Scalar multiplication by natural numbers. -/
|
||||
[nsmul : HMul Nat M M]
|
||||
class NatModule (M : Type u) extends Zero M, Add M, HMul Nat M M where
|
||||
/-- Zero is the right identity for addition. -/
|
||||
add_zero : ∀ a : M, a + 0 = a
|
||||
/-- Addition is commutative. -/
|
||||
add_comm : ∀ a b : M, a + b = b + a
|
||||
/-- Addition is associative. -/
|
||||
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
|
||||
/-- Scalar multiplication by zero is zero. -/
|
||||
zero_nsmul : ∀ a : M, 0 * a = 0
|
||||
zero_hmul : ∀ a : M, 0 * a = 0
|
||||
/-- Scalar multiplication by one is the identity. -/
|
||||
one_nsmul : ∀ a : M, 1 * a = a
|
||||
one_hmul : ∀ a : M, 1 * a = a
|
||||
/-- Scalar multiplication is distributive over addition in the natural numbers. -/
|
||||
add_nsmul : ∀ n m : Nat, ∀ a : M, (n + m) * a = n * a + m * a
|
||||
add_hmul : ∀ n m : Nat, ∀ a : M, (n + m) * a = n * a + m * a
|
||||
/-- Scalar multiplication of zero is zero. -/
|
||||
nsmul_zero : ∀ n : Nat, n * (0 : M) = 0
|
||||
hmul_zero : ∀ n : Nat, n * (0 : M) = 0
|
||||
/-- Scalar multiplication is distributive over addition in the module. -/
|
||||
nsmul_add : ∀ n : Nat, ∀ a b : M, n * (a + b) = n * a + n * b
|
||||
hmul_add : ∀ n : Nat, ∀ a b : M, n * (a + b) = n * a + n * b
|
||||
|
||||
attribute [instance 100] NatModule.toAddCommMonoid NatModule.nsmul
|
||||
attribute [instance 100] NatModule.toZero NatModule.toAdd NatModule.toHMul
|
||||
|
||||
/--
|
||||
A module over the integers, i.e. a type with zero, addition, negation, subtraction, and scalar multiplication by integers,
|
||||
@@ -68,54 +54,83 @@ satisfying appropriate compatibilities.
|
||||
|
||||
Equivalently, an additive commutative group.
|
||||
-/
|
||||
class IntModule (M : Type u) extends AddCommGroup M where
|
||||
class IntModule (M : Type u) extends Zero M, Add M, Neg M, Sub M where
|
||||
/-- Scalar multiplication by natural numbers. -/
|
||||
[nsmul : HMul Nat M M]
|
||||
[hmulNat : HMul Nat M M]
|
||||
/-- Scalar multiplication by integers. -/
|
||||
[zsmul : HMul Int M M]
|
||||
[hmulInt : HMul Int M M]
|
||||
/-- Zero is the right identity for addition. -/
|
||||
add_zero : ∀ a : M, a + 0 = a
|
||||
/-- Addition is commutative. -/
|
||||
add_comm : ∀ a b : M, a + b = b + a
|
||||
/-- Addition is associative. -/
|
||||
add_assoc : ∀ a b c : M, a + b + c = a + (b + c)
|
||||
/-- Scalar multiplication by zero is zero. -/
|
||||
zero_zsmul : ∀ a : M, (0 : Int) * a = 0
|
||||
zero_hmul : ∀ a : M, (0 : Int) * a = 0
|
||||
/-- Scalar multiplication by one is the identity. -/
|
||||
one_zsmul : ∀ a : M, (1 : Int) * a = a
|
||||
one_hmul : ∀ a : M, (1 : Int) * a = a
|
||||
/-- Scalar multiplication is distributive over addition in the integers. -/
|
||||
add_zsmul : ∀ n m : Int, ∀ a : M, (n + m) * a = n * a + m * a
|
||||
add_hmul : ∀ n m : Int, ∀ a : M, (n + m) * a = n * a + m * a
|
||||
/-- Scalar multiplication of zero is zero. -/
|
||||
zsmul_zero : ∀ n : Int, n * (0 : M) = 0
|
||||
/-- Scalar multiplication by integers is distributive over addition in the module. -/
|
||||
zsmul_add : ∀ n : Int, ∀ a b : M, n * (a + b) = n * a + n * b
|
||||
hmul_zero : ∀ n : Int, n * (0 : M) = 0
|
||||
/-- Scalar multiplication is distributive over addition in the module. -/
|
||||
hmul_add : ∀ n : Int, ∀ a b : M, n * (a + b) = n * a + n * b
|
||||
/-- Negation is the left inverse of addition. -/
|
||||
neg_add_cancel : ∀ a : M, -a + a = 0
|
||||
/-- Subtraction is addition of the negative. -/
|
||||
sub_eq_add_neg : ∀ a b : M, a - b = a + -b
|
||||
/-- Scalar multiplication by natural numbers is consistent with scalar multiplication by integers. -/
|
||||
zsmul_natCast_eq_nsmul : ∀ n : Nat, ∀ a : M, (n : Int) * a = n * a
|
||||
hmul_nat : ∀ n : Nat, ∀ a : M, (n : Int) * a = n * a
|
||||
|
||||
attribute [instance 100] IntModule.toAddCommGroup IntModule.zsmul
|
||||
namespace NatModule
|
||||
|
||||
instance (priority := 100) IntModule.toNatModule [I : IntModule M] : NatModule M :=
|
||||
{ I with
|
||||
zero_nsmul a := by rw [← zsmul_natCast_eq_nsmul, Int.natCast_zero, zero_zsmul]
|
||||
one_nsmul a := by rw [← zsmul_natCast_eq_nsmul, Int.natCast_one, one_zsmul]
|
||||
add_nsmul n m a := by rw [← zsmul_natCast_eq_nsmul, Int.natCast_add, add_zsmul, zsmul_natCast_eq_nsmul, zsmul_natCast_eq_nsmul]
|
||||
nsmul_zero n := by rw [← zsmul_natCast_eq_nsmul, zsmul_zero]
|
||||
nsmul_add n a b := by rw [← zsmul_natCast_eq_nsmul, zsmul_add, zsmul_natCast_eq_nsmul, zsmul_natCast_eq_nsmul] }
|
||||
|
||||
namespace AddCommMonoid
|
||||
|
||||
variable {M : Type u} [AddCommMonoid M]
|
||||
variable {M : Type u} [NatModule M]
|
||||
|
||||
theorem zero_add (a : M) : 0 + a = a := by
|
||||
rw [add_comm, add_zero]
|
||||
|
||||
theorem add_left_comm (a b c : M) : a + (b + c) = b + (a + c) := by
|
||||
rw [← add_assoc, ← add_assoc, add_comm a]
|
||||
theorem mul_hmul (n m : Nat) (a : M) : (n * m) * a = n * (m * a) := by
|
||||
induction n with
|
||||
| zero => simp [zero_hmul]
|
||||
| succ n ih =>
|
||||
rw [Nat.add_one_mul, add_hmul, ih, add_hmul, one_hmul]
|
||||
|
||||
end AddCommMonoid
|
||||
instance (priority := 100) (M : Type u) [NatModule M] : SMul Nat M where
|
||||
smul a x := a * x
|
||||
|
||||
namespace AddCommGroup
|
||||
end NatModule
|
||||
|
||||
variable {M : Type u} [AddCommGroup M]
|
||||
open AddCommMonoid
|
||||
namespace IntModule
|
||||
|
||||
attribute [instance 100] IntModule.toZero IntModule.toAdd IntModule.toNeg IntModule.toSub
|
||||
IntModule.hmulNat IntModule.hmulInt
|
||||
|
||||
instance toNatModule (M : Type u) [i : IntModule M] : NatModule M :=
|
||||
{ i with
|
||||
hMul := i.hmulNat.hMul
|
||||
zero_hmul := by simp [← hmul_nat, zero_hmul]
|
||||
one_hmul := by simp [← hmul_nat, one_hmul]
|
||||
hmul_zero := by simp [← hmul_nat, hmul_zero]
|
||||
add_hmul := by simp [← hmul_nat, add_hmul]
|
||||
hmul_add := by simp [← hmul_nat, hmul_add] }
|
||||
|
||||
instance (priority := 100) (M : Type u) [IntModule M] : SMul Nat M where
|
||||
smul a x := a * x
|
||||
|
||||
instance (priority := 100) (M : Type u) [IntModule M] : SMul Int M where
|
||||
smul a x := a * x
|
||||
|
||||
variable {M : Type u} [IntModule M]
|
||||
|
||||
theorem zero_add (a : M) : 0 + a = a := by
|
||||
rw [add_comm, add_zero]
|
||||
|
||||
theorem add_neg_cancel (a : M) : a + -a = 0 := by
|
||||
rw [add_comm, neg_add_cancel]
|
||||
|
||||
theorem add_left_comm (a b c : M) : a + (b + c) = b + (a + c) := by
|
||||
rw [← add_assoc, ← add_assoc, add_comm a]
|
||||
|
||||
theorem add_left_inj {a b : M} (c : M) : a + c = b + c ↔ a = b :=
|
||||
⟨fun h => by simpa [add_assoc, add_neg_cancel, add_zero] using (congrArg (· + -c) h),
|
||||
fun g => congrArg (· + c) g⟩
|
||||
@@ -160,65 +175,35 @@ theorem add_sub_cancel {a b : M} : a + b - b = a := by
|
||||
theorem sub_add_cancel {a b : M} : a - b + b = a := by
|
||||
rw [sub_eq_add_neg, add_assoc, neg_add_cancel, add_zero]
|
||||
|
||||
theorem neg_eq_iff (a b : M) : -a = b ↔ a = -b := by
|
||||
constructor
|
||||
· intro h
|
||||
rw [← neg_neg a, h]
|
||||
· intro h
|
||||
rw [← neg_neg b, h]
|
||||
|
||||
end AddCommGroup
|
||||
|
||||
namespace NatModule
|
||||
|
||||
variable {M : Type u} [NatModule M]
|
||||
|
||||
theorem mul_nsmul (n m : Nat) (a : M) : (n * m) * a = n * (m * a) := by
|
||||
induction n with
|
||||
| zero => simp [zero_nsmul]
|
||||
| succ n ih =>
|
||||
rw [Nat.add_one_mul, add_nsmul, ih, add_nsmul, one_nsmul]
|
||||
|
||||
instance (priority := 100) (M : Type u) [NatModule M] : SMul Nat M where
|
||||
smul a x := a * x
|
||||
|
||||
end NatModule
|
||||
|
||||
namespace IntModule
|
||||
|
||||
open NatModule AddCommGroup
|
||||
|
||||
instance (priority := 100) (M : Type u) [IntModule M] : SMul Int M where
|
||||
smul a x := a * x
|
||||
|
||||
variable {M : Type u} [IntModule M]
|
||||
|
||||
theorem neg_zsmul (n : Int) (a : M) : (-n) * a = - (n * a) := by
|
||||
theorem neg_hmul (n : Int) (a : M) : (-n) * a = - (n * a) := by
|
||||
apply (add_left_inj (n * a)).mp
|
||||
rw [← add_zsmul, Int.add_left_neg, zero_zsmul, neg_add_cancel]
|
||||
rw [← add_hmul, Int.add_left_neg, zero_hmul, neg_add_cancel]
|
||||
|
||||
theorem zsmul_neg (n : Int) (a : M) : n * (-a) = - (n * a) := by
|
||||
theorem hmul_neg (n : Int) (a : M) : n * (-a) = - (n * a) := by
|
||||
apply (add_left_inj (n * a)).mp
|
||||
rw [← zsmul_add, neg_add_cancel, neg_add_cancel, zsmul_zero]
|
||||
rw [← hmul_add, neg_add_cancel, neg_add_cancel, hmul_zero]
|
||||
|
||||
theorem zsmul_sub (k : Int) (a b : M) : k * (a - b) = k * a - k * b := by
|
||||
rw [sub_eq_add_neg, zsmul_add, zsmul_neg, ← sub_eq_add_neg]
|
||||
theorem hmul_sub (k : Int) (a b : M) : k * (a - b) = k * a - k * b := by
|
||||
rw [sub_eq_add_neg, hmul_add, hmul_neg, ← sub_eq_add_neg]
|
||||
|
||||
theorem sub_zsmul (k₁ k₂ : Int) (a : M) : (k₁ - k₂) * a = k₁ * a - k₂ * a := by
|
||||
rw [Int.sub_eq_add_neg, add_zsmul, neg_zsmul, ← sub_eq_add_neg]
|
||||
theorem sub_hmul (k₁ k₂ : Int) (a : M) : (k₁ - k₂) * a = k₁ * a - k₂ * a := by
|
||||
rw [Int.sub_eq_add_neg, add_hmul, neg_hmul, ← sub_eq_add_neg]
|
||||
|
||||
private theorem mul_zsmul_aux (n : Nat) (m : Int) (a : M) :
|
||||
theorem nat_zero_hmul (a : M) : (0 : Nat) * a = 0 := by
|
||||
rw [← hmul_nat, Int.natCast_zero, zero_hmul]
|
||||
|
||||
private theorem nat_mul_hmul (n : Nat) (m : Int) (a : M) :
|
||||
((n : Int) * m) * a = (n : Int) * (m * a) := by
|
||||
induction n with
|
||||
| zero => simp [zero_zsmul]
|
||||
| zero => simp [zero_hmul]
|
||||
| succ n ih =>
|
||||
rw [Int.natCast_add, Int.add_mul, add_zsmul, Int.natCast_one,
|
||||
Int.one_mul, add_zsmul, one_zsmul, ih]
|
||||
rw [Int.natCast_add, Int.add_mul, add_hmul, Int.natCast_one,
|
||||
Int.one_mul, add_hmul, one_hmul, ih]
|
||||
|
||||
theorem mul_zsmul (n m : Int) (a : M) : (n * m) * a = n * (m * a) := by
|
||||
theorem mul_hmul (n m : Int) (a : M) : (n * m) * a = n * (m * a) := by
|
||||
match n with
|
||||
| (n : Nat) => exact mul_zsmul_aux n m a
|
||||
| -(n + 1 : Nat) => rw [Int.neg_mul, neg_zsmul, mul_zsmul_aux, neg_zsmul]
|
||||
| (n : Nat) => exact nat_mul_hmul n m a
|
||||
| -(n + 1 : Nat) => rw [Int.neg_mul, neg_hmul, nat_mul_hmul, neg_hmul]
|
||||
|
||||
end IntModule
|
||||
|
||||
@@ -240,35 +225,31 @@ export NoNatZeroDivisors (no_nat_zero_divisors)
|
||||
namespace NoNatZeroDivisors
|
||||
|
||||
/-- Alternative constructor for `NoNatZeroDivisors` when we have an `IntModule`. -/
|
||||
def mk' {α} [IntModule α]
|
||||
(eq_zero_of_mul_eq_zero : ∀ (k : Nat) (a : α), k ≠ 0 → k * a = 0 → a = 0) :
|
||||
NoNatZeroDivisors α where
|
||||
def mk' {α} [IntModule α] (eq_zero_of_mul_eq_zero : ∀ (k : Nat) (a : α), k ≠ 0 → k * a = 0 → a = 0) : NoNatZeroDivisors α where
|
||||
no_nat_zero_divisors k a b h₁ h₂ := by
|
||||
rw [← AddCommGroup.sub_eq_zero_iff, ← IntModule.zsmul_natCast_eq_nsmul,
|
||||
← IntModule.zsmul_natCast_eq_nsmul, ← IntModule.zsmul_sub,
|
||||
IntModule.zsmul_natCast_eq_nsmul] at h₂
|
||||
rw [← AddCommGroup.sub_eq_zero_iff]
|
||||
rw [← IntModule.sub_eq_zero_iff, ← IntModule.hmul_nat, ← IntModule.hmul_nat, ← IntModule.hmul_sub, IntModule.hmul_nat] at h₂
|
||||
rw [← IntModule.sub_eq_zero_iff]
|
||||
apply eq_zero_of_mul_eq_zero k (a - b) h₁ h₂
|
||||
|
||||
theorem eq_zero_of_mul_eq_zero {α : Type u} [NatModule α] [NoNatZeroDivisors α] {k : Nat} {a : α}
|
||||
: k ≠ 0 → k * a = 0 → a = 0 := by
|
||||
intro h₁ h₂
|
||||
replace h₁ : k ≠ 0 := by intro h; simp [h] at h₁
|
||||
exact no_nat_zero_divisors k a 0 h₁ (by rwa [NatModule.nsmul_zero])
|
||||
exact no_nat_zero_divisors k a 0 h₁ (by rwa [NatModule.hmul_zero])
|
||||
|
||||
end NoNatZeroDivisors
|
||||
|
||||
instance [ToInt α (IntInterval.co lo hi)] [AddCommGroup α] [ToInt.Zero α (IntInterval.co lo hi)] [ToInt.Add α (IntInterval.co lo hi)] : ToInt.Neg α (IntInterval.co lo hi) where
|
||||
instance [ToInt α (IntInterval.co lo hi)] [IntModule α] [ToInt.Zero α (IntInterval.co lo hi)] [ToInt.Add α (IntInterval.co lo hi)] : ToInt.Neg α (IntInterval.co lo hi) where
|
||||
toInt_neg x := by
|
||||
have := (ToInt.Add.toInt_add (-x) x).symm
|
||||
rw [AddCommGroup.neg_add_cancel, ToInt.Zero.toInt_zero, ← ToInt.Zero.wrap_zero (α := α)] at this
|
||||
rw [IntModule.neg_add_cancel, ToInt.Zero.toInt_zero, ← ToInt.Zero.wrap_zero (α := α)] at this
|
||||
rw [IntInterval.wrap_eq_wrap_iff] at this
|
||||
simp at this
|
||||
rw [← ToInt.wrap_toInt]
|
||||
rw [IntInterval.wrap_eq_wrap_iff]
|
||||
simpa
|
||||
|
||||
instance [ToInt α (IntInterval.co lo hi)] [AddCommGroup α] [ToInt.Add α (IntInterval.co lo hi)] [ToInt.Neg α (IntInterval.co lo hi)] : ToInt.Sub α (IntInterval.co lo hi) :=
|
||||
ToInt.Sub.of_sub_eq_add_neg AddCommGroup.sub_eq_add_neg (by simp)
|
||||
instance [ToInt α (IntInterval.co lo hi)] [IntModule α] [ToInt.Add α (IntInterval.co lo hi)] [ToInt.Neg α (IntInterval.co lo hi)] : ToInt.Sub α (IntInterval.co lo hi) :=
|
||||
ToInt.Sub.of_sub_eq_add_neg IntModule.sub_eq_add_neg (by simp)
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -19,9 +19,9 @@ variable [NatModule α]
|
||||
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance : Std.Associative (· + · : α → α → α) where
|
||||
assoc := AddCommMonoid.add_assoc
|
||||
assoc := NatModule.add_assoc
|
||||
local instance : Std.Commutative (· + · : α → α → α) where
|
||||
comm := AddCommMonoid.add_comm
|
||||
comm := NatModule.add_comm
|
||||
|
||||
@[local simp] private theorem exists_true : ∃ (_ : α), True := ⟨0, trivial⟩
|
||||
|
||||
@@ -33,10 +33,10 @@ def Q := Quot (r α)
|
||||
variable {α}
|
||||
|
||||
theorem r_rfl (a : α × α) : r α a a := by
|
||||
cases a; refine ⟨0, ?_⟩; simp [AddCommMonoid.add_zero]; ac_rfl
|
||||
cases a; refine ⟨0, ?_⟩; simp [NatModule.add_zero]; ac_rfl
|
||||
|
||||
theorem r_sym {a b : α × α} : r α a b → r α b a := by
|
||||
cases a; cases b; simp [r]; intro h w; refine ⟨h, ?_⟩; simp [w, AddCommMonoid.add_comm]
|
||||
cases a; cases b; simp [r]; intro h w; refine ⟨h, ?_⟩; simp [w, NatModule.add_comm]
|
||||
|
||||
theorem r_trans {a b c : α × α} : r α a b → r α b c → r α a c := by
|
||||
cases a; cases b; cases c;
|
||||
@@ -63,20 +63,20 @@ def Q.liftOn₂ (q₁ q₂ : Q α)
|
||||
induction q₂ using Quot.ind
|
||||
apply h; assumption; apply r_rfl
|
||||
|
||||
attribute [local simp] Q.mk Q.liftOn₂ AddCommMonoid.add_zero
|
||||
attribute [local simp] Q.mk Q.liftOn₂ NatModule.add_zero
|
||||
|
||||
def Q.ind {β : Q α → Prop} (mk : ∀ (a : α × α), β (Q.mk a)) (q : Q α) : β q :=
|
||||
Quot.ind mk q
|
||||
|
||||
@[local simp] def nsmul (n : Nat) (q : Q α) : (Q α) :=
|
||||
@[local simp] def hmulNat (n : Nat) (q : Q α) : (Q α) :=
|
||||
q.liftOn (fun (a, b) => Q.mk (n * a, n * b))
|
||||
(by intro (a₁, b₁) (a₂, b₂)
|
||||
simp; intro k h; apply Quot.sound; simp
|
||||
refine ⟨n * k, ?_⟩
|
||||
replace h := congrArg (fun x : α => n * x) h
|
||||
simpa [NatModule.nsmul_add] using h)
|
||||
simpa [NatModule.hmul_add] using h)
|
||||
|
||||
@[local simp] def zsmul (n : Int) (q : Q α) : (Q α) :=
|
||||
@[local simp] def hmulInt (n : Int) (q : Q α) : (Q α) :=
|
||||
q.liftOn (fun (a, b) => if n < 0 then Q.mk (n.natAbs * b, n.natAbs * a) else Q.mk (n.natAbs * a, n.natAbs * b))
|
||||
(by intro (a₁, b₁) (a₂, b₂)
|
||||
simp; intro k h;
|
||||
@@ -84,11 +84,11 @@ def Q.ind {β : Q α → Prop} (mk : ∀ (a : α × α), β (Q.mk a)) (q : Q α)
|
||||
· apply Quot.sound; simp
|
||||
refine ⟨n.natAbs * k, ?_⟩
|
||||
replace h := congrArg (fun x : α => n.natAbs * x) h
|
||||
simpa [NatModule.nsmul_add] using h.symm
|
||||
simpa [NatModule.hmul_add] using h.symm
|
||||
· apply Quot.sound; simp
|
||||
refine ⟨n.natAbs * k, ?_⟩
|
||||
replace h := congrArg (fun x : α => n.natAbs * x) h
|
||||
simpa [NatModule.nsmul_add] using h)
|
||||
simpa [NatModule.hmul_add] using h)
|
||||
|
||||
@[local simp] def sub (q₁ q₂ : Q α) : Q α :=
|
||||
Q.liftOn₂ q₁ q₂ (fun (a, b) (c, d) => Q.mk (a + d, c + b))
|
||||
@@ -115,8 +115,8 @@ def Q.ind {β : Q α → Prop} (mk : ∀ (a : α × α), β (Q.mk a)) (q : Q α)
|
||||
exact ⟨k, h.symm⟩)
|
||||
|
||||
attribute [local simp]
|
||||
Quot.liftOn AddCommMonoid.add_zero AddCommMonoid.zero_add NatModule.one_nsmul NatModule.zero_nsmul NatModule.nsmul_zero
|
||||
NatModule.nsmul_add NatModule.add_nsmul
|
||||
Quot.liftOn NatModule.add_zero NatModule.zero_add NatModule.one_hmul NatModule.zero_hmul NatModule.hmul_zero
|
||||
NatModule.hmul_add NatModule.add_hmul
|
||||
|
||||
@[local simp] def zero : Q α :=
|
||||
Q.mk (0, 0)
|
||||
@@ -150,18 +150,18 @@ theorem sub_eq_add_neg (a b : Q α) : sub a b = add a (neg b) := by
|
||||
next a b =>
|
||||
cases a; cases b; simp; apply Quot.sound; simp; refine ⟨0, ?_⟩; ac_rfl
|
||||
|
||||
theorem one_zsmul (a : Q α) : zsmul 1 a = a := by
|
||||
theorem one_hmul (a : Q α) : hmulInt 1 a = a := by
|
||||
induction a using Quot.ind
|
||||
next a => cases a; simp
|
||||
|
||||
theorem zero_zsmul (a : Q α) : zsmul 0 a = zero := by
|
||||
theorem zero_hmul (a : Q α) : hmulInt 0 a = zero := by
|
||||
induction a using Quot.ind
|
||||
next a => cases a; simp
|
||||
|
||||
theorem zsmul_zero (a : Int) : zsmul a (zero : Q α) = zero := by
|
||||
theorem hmul_zero (a : Int) : hmulInt a (zero : Q α) = zero := by
|
||||
simp
|
||||
|
||||
theorem zsmul_add (a : Int) (b c : Q α) : zsmul a (add b c) = add (zsmul a b) (zsmul a c) := by
|
||||
theorem hmul_add (a : Int) (b c : Q α) : hmulInt a (add b c) = add (hmulInt a b) (hmulInt a c) := by
|
||||
induction b using Q.ind
|
||||
induction c using Q.ind
|
||||
next b c =>
|
||||
@@ -172,7 +172,7 @@ theorem zsmul_add (a : Int) (b c : Q α) : zsmul a (add b c) = add (zsmul a b) (
|
||||
simp
|
||||
ac_rfl
|
||||
|
||||
theorem add_zsmul (a b : Int) (c : Q α) : zsmul (a + b) c = add (zsmul a c) (zsmul b c) := by
|
||||
theorem add_hmul (a b : Int) (c : Q α) : hmulInt (a + b) c = add (hmulInt a c) (hmulInt b c) := by
|
||||
induction c using Q.ind
|
||||
next c =>
|
||||
rcases c with ⟨c₁, c₂⟩; simp
|
||||
@@ -183,7 +183,7 @@ theorem add_zsmul (a b : Int) (c : Q α) : zsmul (a + b) c = add (zsmul a c) (zs
|
||||
rw [if_pos (by omega)]
|
||||
apply Quot.sound
|
||||
refine ⟨0, ?_⟩
|
||||
rw [Int.natAbs_add_of_nonpos (by omega) (by omega), NatModule.add_nsmul, NatModule.add_nsmul]
|
||||
rw [Int.natAbs_add_of_nonpos (by omega) (by omega), NatModule.add_hmul, NatModule.add_hmul]
|
||||
ac_rfl
|
||||
· split
|
||||
· apply Quot.sound
|
||||
@@ -213,23 +213,23 @@ theorem add_zsmul (a b : Int) (c : Q α) : zsmul (a + b) c = add (zsmul a c) (zs
|
||||
rw [if_neg (by omega)]
|
||||
apply Quot.sound
|
||||
refine ⟨0, ?_⟩
|
||||
rw [Int.natAbs_add_of_nonneg (by omega) (by omega), NatModule.add_nsmul, NatModule.add_nsmul]
|
||||
rw [Int.natAbs_add_of_nonneg (by omega) (by omega), NatModule.add_hmul, NatModule.add_hmul]
|
||||
ac_rfl
|
||||
|
||||
theorem zsmul_natCast_eq_nsmul (n : Nat) (a : Q α) : zsmul (n : Int) a = nsmul n a := by
|
||||
theorem hmul_nat (n : Nat) (a : Q α) : hmulInt (n : Int) a = hmulNat n a := by
|
||||
induction a using Q.ind
|
||||
next a =>
|
||||
rcases a with ⟨a₁, a₂⟩; simp; omega
|
||||
|
||||
def ofNatModule : IntModule (Q α) := {
|
||||
nsmul := ⟨nsmul⟩,
|
||||
zsmul := ⟨zsmul⟩,
|
||||
hmulNat := ⟨hmulNat⟩,
|
||||
hmulInt := ⟨hmulInt⟩,
|
||||
zero,
|
||||
add, sub, neg,
|
||||
add_comm, add_assoc, add_zero,
|
||||
neg_add_cancel, sub_eq_add_neg,
|
||||
one_zsmul, zero_zsmul, zsmul_zero, zsmul_add, add_zsmul,
|
||||
zsmul_natCast_eq_nsmul
|
||||
one_hmul, zero_hmul, hmul_zero, hmul_add, add_hmul,
|
||||
hmul_nat
|
||||
}
|
||||
|
||||
attribute [instance] ofNatModule
|
||||
@@ -257,7 +257,7 @@ private def rel (h : Equivalence (r α)) (q₁ q₂ : Q α) : Prop :=
|
||||
|
||||
private theorem rel_rfl (h : Equivalence (r α)) (q : Q α) : rel h q q := by
|
||||
induction q using Quot.ind
|
||||
simp [rel, AddCommMonoid.add_comm]
|
||||
simp [rel, NatModule.add_comm]
|
||||
|
||||
private theorem helper (h : Equivalence (r α)) (q₁ q₂ : Q α) : q₁ = q₂ → rel h q₁ q₂ := by
|
||||
intro h; subst q₁; apply rel_rfl h
|
||||
@@ -287,7 +287,7 @@ instance [NatModule α] [AddRightCancel α] [NoNatZeroDivisors α] : NoNatZeroDi
|
||||
simp [r] at h₂
|
||||
rcases h₂ with ⟨k', h₂⟩
|
||||
replace h₂ := AddRightCancel.add_right_cancel _ _ _ h₂
|
||||
simp [← NatModule.nsmul_add] at h₂
|
||||
simp [← NatModule.hmul_add] at h₂
|
||||
replace h₂ := NoNatZeroDivisors.no_nat_zero_divisors k (a₁ + b₂) (a₂ + b₁) h₁ h₂
|
||||
apply Quot.sound; simp [r]; exists 0; simp [h₂]
|
||||
|
||||
@@ -318,7 +318,7 @@ instance [Preorder α] [OrderedAdd α] : Preorder (OfNatModule.Q α) where
|
||||
rcases a with ⟨a₁, a₂⟩
|
||||
change Q.mk _ ≤ Q.mk _
|
||||
simp only [mk_le_mk]
|
||||
simp [AddCommMonoid.add_comm]; exact Preorder.le_refl (a₁ + a₂)
|
||||
simp [NatModule.add_comm]; exact Preorder.le_refl (a₁ + a₂)
|
||||
le_trans {a b c} h₁ h₂ := by
|
||||
induction a using Q.ind
|
||||
induction b using Q.ind
|
||||
@@ -337,12 +337,12 @@ attribute [-simp] Q.mk
|
||||
|
||||
@[local simp] private theorem mk_lt_mk [Preorder α] [OrderedAdd α] {a₁ a₂ b₁ b₂ : α} :
|
||||
Q.mk (a₁, a₂) < Q.mk (b₁, b₂) ↔ a₁ + b₂ < a₂ + b₁ := by
|
||||
simp [Preorder.lt_iff_le_not_le, AddCommMonoid.add_comm]
|
||||
simp [Preorder.lt_iff_le_not_le, NatModule.add_comm]
|
||||
|
||||
@[local simp] private theorem mk_pos [Preorder α] [OrderedAdd α] {a₁ a₂ : α} :
|
||||
0 < Q.mk (a₁, a₂) ↔ a₂ < a₁ := by
|
||||
change Q.mk (0,0) < _ ↔ _
|
||||
simp [mk_lt_mk, AddCommMonoid.zero_add]
|
||||
simp [mk_lt_mk, NatModule.zero_add]
|
||||
|
||||
@[local simp]
|
||||
theorem toQ_le [Preorder α] [OrderedAdd α] {a b : α} : toQ a ≤ toQ b ↔ a ≤ b := by
|
||||
|
||||
@@ -20,9 +20,9 @@ Support for the linear arithmetic module for `IntModule` in `grind`
|
||||
|
||||
namespace Lean.Grind.Linarith
|
||||
abbrev Var := Nat
|
||||
open AddCommMonoid AddCommGroup NatModule IntModule
|
||||
open IntModule
|
||||
|
||||
attribute [local simp] add_zero zero_add zero_zsmul zero_nsmul zsmul_zero one_zsmul
|
||||
attribute [local simp] add_zero zero_add zero_hmul nat_zero_hmul hmul_zero one_hmul
|
||||
|
||||
inductive Expr where
|
||||
| zero
|
||||
@@ -75,10 +75,10 @@ where
|
||||
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [IntModule α] : Std.Associative (· + · : α → α → α) where
|
||||
assoc := AddCommMonoid.add_assoc
|
||||
assoc := IntModule.add_assoc
|
||||
-- Helper instance for `ac_rfl`
|
||||
local instance {α} [IntModule α] : Std.Commutative (· + · : α → α → α) where
|
||||
comm := AddCommMonoid.add_comm
|
||||
comm := IntModule.add_comm
|
||||
|
||||
theorem Poly.denote'_go_eq_denote {α} [IntModule α] (ctx : Context α) (p : Poly) (r : α) : denote'.go ctx r p = p.denote ctx + r := by
|
||||
induction r, p using denote'.go.induct ctx <;> simp [denote'.go, denote]
|
||||
@@ -176,7 +176,7 @@ def Poly.mul (p : Poly) (k : Int) : Poly :=
|
||||
next => simp [*, denote]
|
||||
next =>
|
||||
induction p <;> simp [mul', denote, *]
|
||||
rw [mul_zsmul, zsmul_add]
|
||||
rw [mul_hmul, hmul_add]
|
||||
|
||||
theorem Poly.denote_insert {α} [IntModule α] (ctx : Context α) (k : Int) (v : Var) (p : Poly) :
|
||||
(p.insert k v).denote ctx = p.denote ctx + k * v.denote ctx := by
|
||||
@@ -184,8 +184,8 @@ theorem Poly.denote_insert {α} [IntModule α] (ctx : Context α) (k : Int) (v :
|
||||
next => ac_rfl
|
||||
next h₁ h₂ h₃ =>
|
||||
simp at h₃; simp at h₂; subst h₂
|
||||
rw [add_comm, ← add_assoc, ← add_zsmul, h₃, zero_zsmul, zero_add]
|
||||
next h _ => simp at h; subst h; rw [add_zsmul]; ac_rfl
|
||||
rw [add_comm, ← add_assoc, ← add_hmul, h₃, zero_hmul, zero_add]
|
||||
next h _ => simp at h; subst h; rw [add_hmul]; ac_rfl
|
||||
next ih => rw [ih]; ac_rfl
|
||||
|
||||
attribute [local simp] Poly.denote_insert
|
||||
@@ -205,8 +205,8 @@ theorem Poly.denote_combine' {α} [IntModule α] (ctx : Context α) (fuel : Nat)
|
||||
simp_all +zetaDelta [denote]
|
||||
next h _ =>
|
||||
rw [Int.add_comm] at h
|
||||
rw [add_left_comm, add_assoc, ← add_assoc, ← add_zsmul, h, zero_zsmul, zero_add]
|
||||
next => rw [add_zsmul]; ac_rfl
|
||||
rw [add_left_comm, add_assoc, ← add_assoc, ← add_hmul, h, zero_hmul, zero_add]
|
||||
next => rw [add_hmul]; ac_rfl
|
||||
all_goals ac_rfl
|
||||
|
||||
theorem Poly.denote_combine {α} [IntModule α] (ctx : Context α) (p₁ p₂ : Poly) : (p₁.combine p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
@@ -216,14 +216,14 @@ attribute [local simp] Poly.denote_combine
|
||||
|
||||
theorem Expr.denote_toPoly'_go {α} [IntModule α] {k p} (ctx : Context α) (e : Expr)
|
||||
: (toPoly'.go k e p).denote ctx = k * e.denote ctx + p.denote ctx := by
|
||||
induction k, e using Expr.toPoly'.go.induct generalizing p <;> simp [toPoly'.go, denote, Poly.denote, *, zsmul_add]
|
||||
induction k, e using Expr.toPoly'.go.induct generalizing p <;> simp [toPoly'.go, denote, Poly.denote, *, hmul_add]
|
||||
next => ac_rfl
|
||||
next => rw [sub_eq_add_neg, neg_zsmul, zsmul_add, zsmul_neg]; ac_rfl
|
||||
next => rw [sub_eq_add_neg, neg_hmul, hmul_add, hmul_neg]; ac_rfl
|
||||
next h => simp at h; subst h; simp
|
||||
next ih => simp at ih; rw [ih, mul_zsmul, zsmul_natCast_eq_nsmul]
|
||||
next ih => simp at ih; rw [ih, mul_hmul, IntModule.hmul_nat]
|
||||
next ih => simp at ih; simp [ih]
|
||||
next ih => simp at ih; rw [ih, mul_zsmul]
|
||||
next => rw [zsmul_neg, neg_zsmul]
|
||||
next ih => simp at ih; rw [ih, mul_hmul]
|
||||
next => rw [hmul_neg, neg_hmul]
|
||||
|
||||
theorem Expr.denote_norm {α} [IntModule α] (ctx : Context α) (e : Expr) : e.norm.denote ctx = e.denote ctx := by
|
||||
simp [norm, toPoly', Expr.denote_toPoly'_go, Poly.denote]
|
||||
@@ -280,8 +280,8 @@ def le_le_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
theorem le_le_combine {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
|
||||
: le_le_combine_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx ≤ 0 → p₃.denote' ctx ≤ 0 := by
|
||||
simp [le_le_combine_cert]; intro _ h₁ h₂; subst p₃; simp
|
||||
replace h₁ := zsmul_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
|
||||
replace h₂ := zsmul_nonpos (coe_natAbs_nonneg p₁.leadCoeff) h₂
|
||||
replace h₁ := hmul_int_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
|
||||
replace h₂ := hmul_int_nonpos (coe_natAbs_nonneg p₁.leadCoeff) h₂
|
||||
exact le_add_le h₁ h₂
|
||||
|
||||
def le_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
@@ -292,8 +292,8 @@ def le_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
theorem le_lt_combine {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
|
||||
: le_lt_combine_cert p₁ p₂ p₃ → p₁.denote' ctx ≤ 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
|
||||
simp [-Int.natAbs_pos, -Int.ofNat_pos, le_lt_combine_cert]; intro hp _ h₁ h₂; subst p₃; simp
|
||||
replace h₁ := zsmul_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
|
||||
replace h₂ := zsmul_neg_iff (↑p₁.leadCoeff.natAbs) h₂ |>.mpr hp
|
||||
replace h₁ := hmul_int_nonpos (coe_natAbs_nonneg p₂.leadCoeff) h₁
|
||||
replace h₂ := hmul_int_neg_iff (↑p₁.leadCoeff.natAbs) h₂ |>.mpr hp
|
||||
exact le_add_lt h₁ h₂
|
||||
|
||||
def lt_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
@@ -304,8 +304,8 @@ def lt_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
|
||||
theorem lt_lt_combine {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
|
||||
: lt_lt_combine_cert p₁ p₂ p₃ → p₁.denote' ctx < 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
|
||||
simp [-Int.natAbs_pos, -Int.ofNat_pos, lt_lt_combine_cert]; intro hp₁ hp₂ _ h₁ h₂; subst p₃; simp
|
||||
replace h₁ := zsmul_neg_iff (↑p₂.leadCoeff.natAbs) h₁ |>.mpr hp₁
|
||||
replace h₂ := zsmul_neg_iff (↑p₁.leadCoeff.natAbs) h₂ |>.mpr hp₂
|
||||
replace h₁ := hmul_int_neg_iff (↑p₂.leadCoeff.natAbs) h₁ |>.mpr hp₁
|
||||
replace h₂ := hmul_int_neg_iff (↑p₁.leadCoeff.natAbs) h₂ |>.mpr hp₂
|
||||
exact lt_add_lt h₁ h₂
|
||||
|
||||
def diseq_split_cert (p₁ p₂ : Poly) : Bool :=
|
||||
@@ -320,7 +320,7 @@ theorem diseq_split {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx :
|
||||
next h =>
|
||||
apply Or.inr
|
||||
simp [h₁] at h
|
||||
rw [← neg_pos_iff, neg_zsmul, neg_neg, one_zsmul]; assumption
|
||||
rw [← neg_pos_iff, neg_hmul, neg_neg, one_hmul]; assumption
|
||||
|
||||
theorem diseq_split_resolve {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: diseq_split_cert p₁ p₂ → p₁.denote' ctx ≠ 0 → ¬p₁.denote' ctx < 0 → p₂.denote' ctx < 0 := by
|
||||
@@ -409,7 +409,7 @@ theorem eq_of_le_ge {α} [IntModule α] [PartialOrder α] [OrderedAdd α] (ctx :
|
||||
intro; subst p₂; simp
|
||||
intro h₁ h₂
|
||||
replace h₂ := add_le_left h₂ (p₁.denote ctx)
|
||||
rw [add_comm, neg_zsmul, one_zsmul, ← sub_eq_add_neg, sub_self, zero_add] at h₂
|
||||
rw [add_comm, neg_hmul, one_hmul, ← sub_eq_add_neg, sub_self, zero_add] at h₂
|
||||
exact PartialOrder.le_antisymm h₁ h₂
|
||||
|
||||
/-!
|
||||
@@ -429,7 +429,7 @@ def zero_lt_one_cert (p : Poly) : Bool :=
|
||||
|
||||
theorem zero_lt_one {α} [Ring α] [Preorder α] [OrderedRing α] (ctx : Context α) (p : Poly)
|
||||
: zero_lt_one_cert p → (0 : Var).denote ctx = One.one → p.denote' ctx < 0 := by
|
||||
simp [zero_lt_one_cert]; intro _ h; subst p; simp [Poly.denote, h, One.one, neg_zsmul]
|
||||
simp [zero_lt_one_cert]; intro _ h; subst p; simp [Poly.denote, h, One.one, neg_hmul]
|
||||
rw [neg_lt_iff, neg_zero]; apply OrderedRing.zero_lt_one
|
||||
|
||||
def zero_ne_one_cert (p : Poly) : Bool :=
|
||||
@@ -478,7 +478,7 @@ def eq_coeff_cert (p₁ p₂ : Poly) (k : Nat) :=
|
||||
|
||||
theorem eq_coeff {α} [IntModule α] [NoNatZeroDivisors α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
|
||||
: eq_coeff_cert p₁ p₂ k → p₁.denote' ctx = 0 → p₂.denote' ctx = 0 := by
|
||||
simp [eq_coeff_cert]; intro h _; subst p₁; simp [*, zsmul_natCast_eq_nsmul]
|
||||
simp [eq_coeff_cert]; intro h _; subst p₁; simp [*, hmul_nat]
|
||||
exact NoNatZeroDivisors.eq_zero_of_mul_eq_zero h
|
||||
|
||||
def coeff_cert (p₁ p₂ : Poly) (k : Nat) :=
|
||||
@@ -490,7 +490,7 @@ theorem le_coeff {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Con
|
||||
have : ↑k > (0 : Int) := Int.natCast_pos.mpr h
|
||||
intro h₁; apply Classical.byContradiction
|
||||
intro h₂; replace h₂ := LinearOrder.lt_of_not_le h₂
|
||||
replace h₂ := zsmul_pos_iff (↑k) h₂ |>.mpr this
|
||||
replace h₂ := hmul_int_pos_iff (↑k) h₂ |>.mpr this
|
||||
exact Preorder.lt_irrefl 0 (Preorder.lt_of_lt_of_le h₂ h₁)
|
||||
|
||||
theorem lt_coeff {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
|
||||
@@ -499,11 +499,11 @@ theorem lt_coeff {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Con
|
||||
have : ↑k > (0 : Int) := Int.natCast_pos.mpr h
|
||||
intro h₁; apply Classical.byContradiction
|
||||
intro h₂; replace h₂ := LinearOrder.le_of_not_lt h₂
|
||||
replace h₂ := zsmul_nonneg (Int.le_of_lt this) h₂
|
||||
replace h₂ := hmul_int_nonneg (Int.le_of_lt this) h₂
|
||||
exact Preorder.lt_irrefl 0 (Preorder.lt_of_le_of_lt h₂ h₁)
|
||||
|
||||
theorem diseq_neg {α} [IntModule α] (ctx : Context α) (p p' : Poly) : p' == p.mul (-1) → p.denote' ctx ≠ 0 → p'.denote' ctx ≠ 0 := by
|
||||
simp; intro _ _; subst p'; simp [neg_zsmul]
|
||||
simp; intro _ _; subst p'; simp [neg_hmul]
|
||||
intro h; replace h := congrArg (- ·) h; simp [neg_neg, neg_zero] at h
|
||||
contradiction
|
||||
|
||||
@@ -522,8 +522,8 @@ theorem eq_diseq_subst {α} [IntModule α] [NoNatZeroDivisors α] (ctx : Context
|
||||
have : (k₁.natAbs : Int) * Poly.denote ctx p₂ = 0 := by
|
||||
cases Int.natAbs_eq_iff.mp (Eq.refl k₁.natAbs)
|
||||
next h => rw [← h]; assumption
|
||||
next h => replace h := congrArg (- ·) h; simp at h; rw [← h, neg_zsmul, h₃, neg_zero]
|
||||
simpa [zsmul_natCast_eq_nsmul] using this
|
||||
next h => replace h := congrArg (- ·) h; simp at h; rw [← h, IntModule.neg_hmul, h₃, IntModule.neg_zero]
|
||||
simpa [hmul_nat] using this
|
||||
have := NoNatZeroDivisors.eq_zero_of_mul_eq_zero hne this
|
||||
contradiction
|
||||
|
||||
@@ -547,7 +547,7 @@ def eq_le_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
|
||||
theorem eq_le_subst {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (x : Var) (p₁ p₂ p₃ : Poly)
|
||||
: eq_le_subst_cert x p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx ≤ 0 → p₃.denote' ctx ≤ 0 := by
|
||||
simp [eq_le_subst_cert]; intro h _ h₁ h₂; subst p₃; simp [h₁]
|
||||
exact zsmul_nonpos h h₂
|
||||
exact hmul_int_nonpos h h₂
|
||||
|
||||
def eq_lt_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
|
||||
let a := p₁.coeff x
|
||||
@@ -557,7 +557,7 @@ def eq_lt_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
|
||||
theorem eq_lt_subst {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (x : Var) (p₁ p₂ p₃ : Poly)
|
||||
: eq_lt_subst_cert x p₁ p₂ p₃ → p₁.denote' ctx = 0 → p₂.denote' ctx < 0 → p₃.denote' ctx < 0 := by
|
||||
simp [eq_lt_subst_cert]; intro h _ h₁ h₂; subst p₃; simp [h₁]
|
||||
exact zsmul_neg_iff (p₁.coeff x) h₂ |>.mpr h
|
||||
exact hmul_int_neg_iff (p₁.coeff x) h₂ |>.mpr h
|
||||
|
||||
def eq_eq_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
|
||||
let a := p₁.coeff x
|
||||
|
||||
@@ -26,15 +26,22 @@ class ExistsAddOfLT (α : Type u) [LT α] [Zero α] [Add α] where
|
||||
|
||||
namespace OrderedAdd
|
||||
|
||||
open AddCommMonoid NatModule
|
||||
open NatModule
|
||||
|
||||
section
|
||||
|
||||
variable {M : Type u} [Preorder M] [AddCommMonoid M] [OrderedAdd M]
|
||||
variable {M : Type u} [Preorder M] [NatModule M] [OrderedAdd M]
|
||||
|
||||
theorem add_le_right_iff {a b : M} (c : M) : a ≤ b ↔ c + a ≤ c + b := by
|
||||
rw [add_comm c a, add_comm c b, add_le_left_iff]
|
||||
|
||||
theorem hmul_le_hmul {k : Nat} {a b : M} (h : a ≤ b) : k * a ≤ k * b := by
|
||||
induction k with
|
||||
| zero => simp [zero_hmul, Preorder.le_refl]
|
||||
| succ k ih =>
|
||||
rw [add_hmul, one_hmul, add_hmul, one_hmul]
|
||||
exact Preorder.le_trans ((add_le_left_iff a).mp ih) ((add_le_right_iff (k * b)).mp h)
|
||||
|
||||
theorem add_le_left {a b : M} (h : a ≤ b) (c : M) : a + c ≤ b + c :=
|
||||
(add_le_left_iff c).mp h
|
||||
|
||||
@@ -66,6 +73,36 @@ theorem add_lt_left_iff {a b : M} (c : M) : a < b ↔ a + c < b + c := by
|
||||
theorem add_lt_right_iff {a b : M} (c : M) : a < b ↔ c + a < c + b := by
|
||||
rw [add_comm c a, add_comm c b, add_lt_left_iff]
|
||||
|
||||
theorem hmul_lt_hmul_iff (k : Nat) {a b : M} (h : a < b) : k * a < k * b ↔ 0 < k := by
|
||||
induction k with
|
||||
| zero => simp [zero_hmul, Preorder.lt_irrefl]
|
||||
| succ k ih =>
|
||||
rw [add_hmul, one_hmul, add_hmul, one_hmul]
|
||||
simp only [Nat.zero_lt_succ, iff_true]
|
||||
by_cases hk : 0 < k
|
||||
· simp only [hk, iff_true] at ih
|
||||
exact Preorder.lt_trans ((add_lt_left_iff a).mp ih) ((add_lt_right_iff (k * b)).mp h)
|
||||
· simp [Nat.eq_zero_of_not_pos hk, zero_hmul, zero_add, h]
|
||||
|
||||
theorem hmul_pos_iff {k : Nat} {a : M} (h : 0 < a) : 0 < k * a ↔ 0 < k:= by
|
||||
rw [← hmul_lt_hmul_iff k h, hmul_zero]
|
||||
|
||||
theorem hmul_nonneg {k : Nat} {a : M} (h : 0 ≤ a) : 0 ≤ k * a := by
|
||||
have := hmul_le_hmul (k := k) h
|
||||
rwa [hmul_zero] at this
|
||||
|
||||
theorem hmul_le_hmul_of_le_of_le_of_nonneg
|
||||
{k₁ k₂ : Nat} {x y : M} (hk : k₁ ≤ k₂) (h : x ≤ y) (w : 0 ≤ x) :
|
||||
k₁ * x ≤ k₂ * y := by
|
||||
apply Preorder.le_trans
|
||||
· change k₁ * x ≤ k₂ * x
|
||||
obtain ⟨k', rfl⟩ := Nat.exists_eq_add_of_le hk
|
||||
rw [add_hmul]
|
||||
conv => lhs; rw [← add_zero (k₁ * x)]
|
||||
rw [← add_le_right_iff]
|
||||
exact hmul_nonneg w
|
||||
· exact hmul_le_hmul h
|
||||
|
||||
theorem add_le_add {a b c d : M} (hab : a ≤ b) (hcd : c ≤ d) : a + c ≤ b + d :=
|
||||
Preorder.le_trans (add_le_right a hcd) (add_le_left hab d)
|
||||
|
||||
@@ -73,90 +110,44 @@ end
|
||||
|
||||
section
|
||||
|
||||
variable {M : Type u} [Preorder M] [NatModule M] [OrderedAdd M]
|
||||
|
||||
theorem nsmul_le_nsmul {k : Nat} {a b : M} (h : a ≤ b) : k * a ≤ k * b := by
|
||||
induction k with
|
||||
| zero => simp [zero_nsmul, Preorder.le_refl]
|
||||
| succ k ih =>
|
||||
rw [add_nsmul, one_nsmul, add_nsmul, one_nsmul]
|
||||
exact Preorder.le_trans ((add_le_left_iff a).mp ih) ((add_le_right_iff (k * b)).mp h)
|
||||
|
||||
theorem nsmul_lt_nsmul_iff (k : Nat) {a b : M} (h : a < b) : k * a < k * b ↔ 0 < k := by
|
||||
induction k with
|
||||
| zero => simp [zero_nsmul, Preorder.lt_irrefl]
|
||||
| succ k ih =>
|
||||
rw [add_nsmul, one_nsmul, add_nsmul, one_nsmul]
|
||||
simp only [Nat.zero_lt_succ, iff_true]
|
||||
by_cases hk : 0 < k
|
||||
· simp only [hk, iff_true] at ih
|
||||
exact Preorder.lt_trans ((add_lt_left_iff a).mp ih) ((add_lt_right_iff (k * b)).mp h)
|
||||
· simp [Nat.eq_zero_of_not_pos hk, zero_nsmul, zero_add, h]
|
||||
|
||||
theorem nsmul_pos_iff {k : Nat} {a : M} (h : 0 < a) : 0 < k * a ↔ 0 < k:= by
|
||||
rw [← nsmul_lt_nsmul_iff k h, nsmul_zero]
|
||||
|
||||
theorem nsmul_nonneg {k : Nat} {a : M} (h : 0 ≤ a) : 0 ≤ k * a := by
|
||||
have := nsmul_le_nsmul (k := k) h
|
||||
rwa [nsmul_zero] at this
|
||||
|
||||
theorem nsmul_le_nsmul_of_le_of_le_of_nonneg
|
||||
{k₁ k₂ : Nat} {x y : M} (hk : k₁ ≤ k₂) (h : x ≤ y) (w : 0 ≤ x) :
|
||||
k₁ * x ≤ k₂ * y := by
|
||||
apply Preorder.le_trans
|
||||
· change k₁ * x ≤ k₂ * x
|
||||
obtain ⟨k', rfl⟩ := Nat.exists_eq_add_of_le hk
|
||||
rw [add_nsmul]
|
||||
conv => lhs; rw [← add_zero (k₁ * x)]
|
||||
rw [← add_le_right_iff]
|
||||
exact nsmul_nonneg w
|
||||
· exact nsmul_le_nsmul h
|
||||
|
||||
end
|
||||
|
||||
section
|
||||
|
||||
open AddCommGroup
|
||||
variable {M : Type u} [Preorder M] [AddCommGroup M] [OrderedAdd M]
|
||||
variable {M : Type u} [Preorder M] [IntModule M] [OrderedAdd M]
|
||||
|
||||
theorem neg_le_iff {a b : M} : -a ≤ b ↔ -b ≤ a := by
|
||||
rw [OrderedAdd.add_le_left_iff a, neg_add_cancel]
|
||||
conv => rhs; rw [OrderedAdd.add_le_left_iff b, neg_add_cancel]
|
||||
rw [OrderedAdd.add_le_left_iff a, IntModule.neg_add_cancel]
|
||||
conv => rhs; rw [OrderedAdd.add_le_left_iff b, IntModule.neg_add_cancel]
|
||||
rw [add_comm]
|
||||
|
||||
end
|
||||
section
|
||||
|
||||
variable {M : Type u} [Preorder M] [IntModule M] [OrderedAdd M]
|
||||
open AddCommGroup IntModule
|
||||
|
||||
theorem zsmul_pos_iff (k : Int) {x : M} (h : 0 < x) : 0 < k * x ↔ 0 < k :=
|
||||
theorem hmul_int_pos_iff (k : Int) {x : M} (h : 0 < x) : 0 < k * x ↔ 0 < k :=
|
||||
match k with
|
||||
| (k + 1 : Nat) => by
|
||||
simpa [zsmul_zero, ← zsmul_natCast_eq_nsmul] using nsmul_lt_nsmul_iff (k := k + 1) h
|
||||
| (0 : Nat) => by simp [zero_zsmul]; exact Preorder.lt_irrefl 0
|
||||
simpa [IntModule.hmul_zero, ← IntModule.hmul_nat] using hmul_lt_hmul_iff (k := k + 1) h
|
||||
| (0 : Nat) => by simp [IntModule.zero_hmul]; exact Preorder.lt_irrefl 0
|
||||
| -(k + 1 : Nat) => by
|
||||
have : ¬ (k : Int) + 1 < 0 := by omega
|
||||
simp [this]; clear this
|
||||
rw [neg_zsmul]
|
||||
rw [IntModule.neg_hmul]
|
||||
rw [Preorder.lt_iff_le_not_le]
|
||||
simp
|
||||
intro h'
|
||||
rw [OrderedAdd.neg_le_iff, neg_zero]
|
||||
simpa [zsmul_zero, ← zsmul_natCast_eq_nsmul] using
|
||||
nsmul_le_nsmul (k := k + 1) (Preorder.le_of_lt h)
|
||||
rw [OrderedAdd.neg_le_iff, IntModule.neg_zero]
|
||||
simpa [IntModule.hmul_zero, ← IntModule.hmul_nat] using
|
||||
hmul_le_hmul (k := k + 1) (Preorder.le_of_lt h)
|
||||
|
||||
theorem zsmul_nonneg {k : Int} {x : M} (h : 0 ≤ k) (hx : 0 ≤ x) : 0 ≤ k * x :=
|
||||
theorem hmul_int_nonneg {k : Int} {x : M} (h : 0 ≤ k) (hx : 0 ≤ x) : 0 ≤ k * x :=
|
||||
match k, h with
|
||||
| (k : Nat), _ => by
|
||||
simpa [zsmul_natCast_eq_nsmul] using nsmul_nonneg hx
|
||||
simpa [IntModule.hmul_nat] using OrderedAdd.hmul_nonneg hx
|
||||
|
||||
end
|
||||
|
||||
section
|
||||
variable {M : Type u} [Preorder M] [AddCommGroup M] [OrderedAdd M]
|
||||
variable {M : Type u} [Preorder M] [IntModule M] [OrderedAdd M]
|
||||
|
||||
open AddCommGroup
|
||||
open IntModule
|
||||
|
||||
theorem le_neg_iff {a b : M} : a ≤ -b ↔ b ≤ -a := by
|
||||
conv => lhs; rw [← neg_neg a]
|
||||
@@ -177,40 +168,31 @@ theorem neg_pos_iff {a : M} : 0 < -a ↔ a < 0 := by
|
||||
rw [lt_neg_iff, neg_zero]
|
||||
|
||||
theorem sub_nonneg_iff {a b : M} : 0 ≤ a - b ↔ b ≤ a := by
|
||||
rw [add_le_left_iff b, zero_add, sub_add_cancel]
|
||||
rw [add_le_left_iff b, IntModule.zero_add, sub_add_cancel]
|
||||
|
||||
theorem sub_pos_iff {a b : M} : 0 < a - b ↔ b < a := by
|
||||
rw [add_lt_left_iff b, zero_add, sub_add_cancel]
|
||||
rw [add_lt_left_iff b, IntModule.zero_add, sub_add_cancel]
|
||||
|
||||
end
|
||||
theorem hmul_int_neg_iff (k : Int) {a : M} (h : a < 0) : k * a < 0 ↔ 0 < k := by
|
||||
simpa [IntModule.hmul_neg, neg_pos_iff] using hmul_int_pos_iff k (neg_pos_iff.mpr h)
|
||||
|
||||
section
|
||||
theorem hmul_int_nonpos {k : Int} {a : M} (hk : 0 ≤ k) (ha : a ≤ 0) : k * a ≤ 0 := by
|
||||
simpa [IntModule.hmul_neg, neg_nonneg_iff] using hmul_int_nonneg hk (neg_nonneg_iff.mpr ha)
|
||||
|
||||
variable {M : Type u} [Preorder M] [IntModule M] [OrderedAdd M]
|
||||
open IntModule
|
||||
theorem hmul_int_le_hmul_int {a b : M} {k : Int} (hk : 0 ≤ k) (h : a ≤ b) : k * a ≤ k * b := by
|
||||
simpa [hmul_sub, sub_nonneg_iff] using hmul_int_nonneg hk (sub_nonneg_iff.mpr h)
|
||||
|
||||
theorem zsmul_neg_iff (k : Int) {a : M} (h : a < 0) : k * a < 0 ↔ 0 < k := by
|
||||
simpa [IntModule.zsmul_neg, neg_pos_iff] using zsmul_pos_iff k (neg_pos_iff.mpr h)
|
||||
theorem hmul_int_lt_hmul_int_iff (k : Int) {a b : M} (h : a < b) : k * a < k * b ↔ 0 < k := by
|
||||
simpa [hmul_sub, sub_pos_iff] using hmul_int_pos_iff k (sub_pos_iff.mpr h)
|
||||
|
||||
theorem zsmul_nonpos {k : Int} {a : M} (hk : 0 ≤ k) (ha : a ≤ 0) : k * a ≤ 0 := by
|
||||
simpa [IntModule.zsmul_neg, neg_nonneg_iff] using zsmul_nonneg hk (neg_nonneg_iff.mpr ha)
|
||||
|
||||
theorem zsmul_le_zsmul {a b : M} {k : Int} (hk : 0 ≤ k) (h : a ≤ b) : k * a ≤ k * b := by
|
||||
simpa [zsmul_sub, sub_nonneg_iff] using zsmul_nonneg hk (sub_nonneg_iff.mpr h)
|
||||
|
||||
theorem zsmul_lt_zsmul_iff (k : Int) {a b : M} (h : a < b) : k * a < k * b ↔ 0 < k := by
|
||||
simpa [zsmul_sub, sub_pos_iff] using zsmul_pos_iff k (sub_pos_iff.mpr h)
|
||||
|
||||
theorem zsmul_le_zsmul_of_le_of_le_of_nonneg_of_nonneg
|
||||
theorem hmul_int_le_hmul_int_of_le_of_le_of_nonneg_of_nonneg
|
||||
{k₁ k₂ : Int} {x y : M} (hk : k₁ ≤ k₂) (h : x ≤ y) (w : 0 ≤ k₁) (w' : 0 ≤ x) :
|
||||
k₁ * x ≤ k₂ * y := by
|
||||
apply Preorder.le_trans
|
||||
· have : 0 ≤ k₁ * (y - x) := zsmul_nonneg w (sub_nonneg_iff.mpr h)
|
||||
rwa [IntModule.zsmul_sub, sub_nonneg_iff] at this
|
||||
· have : 0 ≤ (k₂ - k₁) * y := zsmul_nonneg (Int.sub_nonneg.mpr hk) (Preorder.le_trans w' h)
|
||||
rwa [IntModule.sub_zsmul, sub_nonneg_iff] at this
|
||||
|
||||
end
|
||||
· have : 0 ≤ k₁ * (y - x) := hmul_int_nonneg w (sub_nonneg_iff.mpr h)
|
||||
rwa [IntModule.hmul_sub, sub_nonneg_iff] at this
|
||||
· have : 0 ≤ (k₂ - k₁) * y := hmul_int_nonneg (Int.sub_nonneg.mpr hk) (Preorder.le_trans w' h)
|
||||
rwa [IntModule.sub_hmul, sub_nonneg_iff] at this
|
||||
|
||||
end OrderedAdd
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ variable [Preorder R] [OrderedRing R]
|
||||
theorem neg_one_lt_zero : (-1 : R) < 0 := by
|
||||
have h := zero_lt_one (R := R)
|
||||
have := OrderedAdd.add_lt_left h (-1)
|
||||
rw [AddCommMonoid.zero_add, AddCommGroup.add_neg_cancel] at this
|
||||
rw [Semiring.zero_add, Ring.add_neg_cancel] at this
|
||||
assumption
|
||||
|
||||
theorem ofNat_nonneg (x : Nat) : (OfNat.ofNat x : R) ≥ 0 := by
|
||||
@@ -48,7 +48,7 @@ theorem ofNat_nonneg (x : Nat) : (OfNat.ofNat x : R) ≥ 0 := by
|
||||
have := OrderedRing.zero_lt_one (R := R)
|
||||
rw [Semiring.ofNat_succ]
|
||||
replace ih := OrderedAdd.add_le_left ih 1
|
||||
rw [AddCommMonoid.zero_add] at ih
|
||||
rw [Semiring.zero_add] at ih
|
||||
have := Preorder.lt_of_lt_of_le this ih
|
||||
exact Preorder.le_of_lt this
|
||||
|
||||
@@ -62,8 +62,8 @@ instance [Ring α] [Preorder α] [OrderedRing α] : IsCharP α 0 := IsCharP.mk'
|
||||
next x =>
|
||||
rw [Semiring.ofNat_succ] at h
|
||||
replace h := congrArg (· - 1) h; simp at h
|
||||
rw [Ring.sub_eq_add_neg, Semiring.add_assoc, AddCommGroup.add_neg_cancel,
|
||||
Ring.sub_eq_add_neg, AddCommMonoid.zero_add, Semiring.add_zero] at h
|
||||
rw [Ring.sub_eq_add_neg, Semiring.add_assoc, Ring.add_neg_cancel,
|
||||
Ring.sub_eq_add_neg, Semiring.zero_add, Semiring.add_zero] at h
|
||||
have h₁ : (OfNat.ofNat x : α) < 0 := by
|
||||
have := OrderedRing.neg_one_lt_zero (R := α)
|
||||
rw [h]; assumption
|
||||
@@ -110,26 +110,26 @@ open OrderedAdd
|
||||
|
||||
theorem mul_le_mul_of_nonpos_left {a b c : R} (h : a ≤ b) (h' : c ≤ 0) : c * b ≤ c * a := by
|
||||
have := mul_le_mul_of_nonneg_left h (neg_nonneg_iff.mpr h')
|
||||
rwa [Ring.neg_mul, Ring.neg_mul, neg_le_iff, AddCommGroup.neg_neg] at this
|
||||
rwa [Ring.neg_mul, Ring.neg_mul, neg_le_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_le_mul_of_nonpos_right {a b c : R} (h : a ≤ b) (h' : c ≤ 0) : b * c ≤ a * c := by
|
||||
have := mul_le_mul_of_nonneg_right h (neg_nonneg_iff.mpr h')
|
||||
rwa [Ring.mul_neg, Ring.mul_neg, neg_le_iff, AddCommGroup.neg_neg] at this
|
||||
rwa [Ring.mul_neg, Ring.mul_neg, neg_le_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_lt_mul_of_neg_left {a b c : R} (h : a < b) (h' : c < 0) : c * b < c * a := by
|
||||
have := mul_lt_mul_of_pos_left h (neg_pos_iff.mpr h')
|
||||
rwa [Ring.neg_mul, Ring.neg_mul, neg_lt_iff, AddCommGroup.neg_neg] at this
|
||||
rwa [Ring.neg_mul, Ring.neg_mul, neg_lt_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_lt_mul_of_neg_right {a b c : R} (h : a < b) (h' : c < 0) : b * c < a * c := by
|
||||
have := mul_lt_mul_of_pos_right h (neg_pos_iff.mpr h')
|
||||
rwa [Ring.mul_neg, Ring.mul_neg, neg_lt_iff, AddCommGroup.neg_neg] at this
|
||||
rwa [Ring.mul_neg, Ring.mul_neg, neg_lt_iff, IntModule.neg_neg] at this
|
||||
|
||||
theorem mul_nonneg {a b : R} (h₁ : 0 ≤ a) (h₂ : 0 ≤ b) : 0 ≤ a * b := by
|
||||
simpa [Semiring.zero_mul] using mul_le_mul_of_nonneg_right h₁ h₂
|
||||
|
||||
theorem mul_nonneg_of_nonpos_of_nonpos {a b : R} (h₁ : a ≤ 0) (h₂ : b ≤ 0) : 0 ≤ a * b := by
|
||||
have := mul_nonneg (neg_nonneg_iff.mpr h₁) (neg_nonneg_iff.mpr h₂)
|
||||
simpa [Ring.neg_mul, Ring.mul_neg, AddCommGroup.neg_neg] using this
|
||||
simpa [Ring.neg_mul, Ring.mul_neg, Ring.neg_neg] using this
|
||||
|
||||
theorem mul_nonpos_of_nonneg_of_nonpos {a b : R} (h₁ : 0 ≤ a) (h₂ : b ≤ 0) : a * b ≤ 0 := by
|
||||
rw [← neg_nonneg_iff, ← Ring.mul_neg]
|
||||
@@ -144,7 +144,7 @@ theorem mul_pos {a b : R} (h₁ : 0 < a) (h₂ : 0 < b) : 0 < a * b := by
|
||||
|
||||
theorem mul_pos_of_neg_of_neg {a b : R} (h₁ : a < 0) (h₂ : b < 0) : 0 < a * b := by
|
||||
have := mul_pos (neg_pos_iff.mpr h₁) (neg_pos_iff.mpr h₂)
|
||||
simpa [Ring.neg_mul, Ring.mul_neg, AddCommGroup.neg_neg] using this
|
||||
simpa [Ring.neg_mul, Ring.mul_neg, Ring.neg_neg] using this
|
||||
|
||||
theorem mul_neg_of_pos_of_neg {a b : R} (h₁ : 0 < a) (h₂ : b < 0) : a * b < 0 := by
|
||||
rw [← neg_pos_iff, ← Ring.mul_neg]
|
||||
|
||||
@@ -15,7 +15,7 @@ public import Init.Grind.Module.Basic
|
||||
public section
|
||||
|
||||
/-!
|
||||
# Commutative ring typeclasses for internal use in `grind`.
|
||||
# A monolithic commutative ring typeclass for internal use in `grind`.
|
||||
|
||||
The `Lean.Grind.CommRing` class will be used to convert expressions into the internal representation via polynomials,
|
||||
with coefficients expressed via `OfNat` and `Neg`.
|
||||
@@ -52,14 +52,12 @@ class Semiring (α : Type u) extends Add α, Mul α, HPow α Nat α where
|
||||
The field `ofNat_eq_natCast` ensures that these are (propositionally) equal to the values of `natCast`.
|
||||
-/
|
||||
[ofNat : ∀ n, OfNat α n]
|
||||
/-- Scalar multiplication by natural numbers. -/
|
||||
[nsmul : HMul Nat α α]
|
||||
/-- Zero is the right identity for addition. -/
|
||||
add_zero : ∀ a : α, a + 0 = a
|
||||
/-- Addition is commutative. -/
|
||||
add_comm : ∀ a b : α, a + b = b + a
|
||||
/-- Addition is associative. -/
|
||||
add_assoc : ∀ a b c : α, a + b + c = a + (b + c)
|
||||
/-- Addition is commutative. -/
|
||||
add_comm : ∀ a b : α, a + b = b + a
|
||||
/-- Zero is the right identity for addition. -/
|
||||
add_zero : ∀ a : α, a + 0 = a
|
||||
/-- Multiplication is associative. -/
|
||||
mul_assoc : ∀ a b c : α, a * b * c = a * (b * c)
|
||||
/-- One is the right identity for multiplication. -/
|
||||
@@ -82,7 +80,6 @@ class Semiring (α : Type u) extends Add α, Mul α, HPow α Nat α where
|
||||
ofNat_succ : ∀ a : Nat, OfNat.ofNat (α := α) (a + 1) = OfNat.ofNat a + 1 := by intros; rfl
|
||||
/-- Numerals are consistently defined with respect to the canonical map from natural numbers. -/
|
||||
ofNat_eq_natCast : ∀ n : Nat, OfNat.ofNat (α := α) n = Nat.cast n := by intros; rfl
|
||||
nsmul_eq_natCast_mul : ∀ n : Nat, ∀ a : α, HMul.hMul (α := Nat) n a = Nat.cast n * a := by intros; rfl
|
||||
|
||||
/--
|
||||
A ring, i.e. a type equipped with addition, negation, multiplication, and a map from the integers,
|
||||
@@ -93,16 +90,10 @@ Use `CommRing` if the multiplication is commutative.
|
||||
class Ring (α : Type u) extends Semiring α, Neg α, Sub α where
|
||||
/-- In every ring there is a canonical map from the integers to the ring. -/
|
||||
[intCast : IntCast α]
|
||||
/-- Scalar multiplication by integers. -/
|
||||
[zsmul : HMul Int α α]
|
||||
/-- Negation is the left inverse of addition. -/
|
||||
neg_add_cancel : ∀ a : α, -a + a = 0
|
||||
/-- Subtraction is addition of the negative. -/
|
||||
sub_eq_add_neg : ∀ a b : α, a - b = a + -b
|
||||
/-- Scalar multiplication by the negation of an integer is the negation of scalar multiplication by that integer. -/
|
||||
neg_zsmul : ∀ (i : Int) (a : α), HMul.hMul (α := Int) (-i : Int) a = -(HMul.hMul (α := Int) i a)
|
||||
/-- Scalar multiplication by natural numbers is consistent with scalar multiplication by integers. -/
|
||||
zsmul_natCast_eq_nsmul : ∀ n : Nat, ∀ a : α, HMul.hMul (α := Int) (n : Int) a = HMul.hMul (α := Nat) n a := by intros; rfl
|
||||
/-- The canonical map from the integers is consistent with the canonical map from the natural numbers. -/
|
||||
intCast_ofNat : ∀ n : Nat, Int.cast (OfNat.ofNat (α := Int) n) = OfNat.ofNat (α := α) n := by intros; rfl
|
||||
/-- The canonical map from the integers is consistent with negation. -/
|
||||
@@ -141,32 +132,27 @@ example [CommRing α] : (CommSemiring.toSemiring : Semiring α) = (Ring.toSemiri
|
||||
|
||||
namespace Semiring
|
||||
|
||||
open NatModule
|
||||
|
||||
variable {α : Type u} [Semiring α]
|
||||
|
||||
theorem natCast_zero : ((0 : Nat) : α) = 0 := by
|
||||
rw [← ofNat_eq_natCast 0]
|
||||
theorem natCast_zero : ((0 : Nat) : α) = 0 := (ofNat_eq_natCast 0).symm
|
||||
theorem natCast_one : ((1 : Nat) : α) = 1 := (ofNat_eq_natCast 1).symm
|
||||
|
||||
theorem ofNat_add (a b : Nat) : OfNat.ofNat (α := α) (a + b) = OfNat.ofNat a + OfNat.ofNat b := by
|
||||
induction b with
|
||||
| zero => rw [Nat.add_zero, add_zero]
|
||||
| zero => simp [Nat.add_zero, add_zero]
|
||||
| succ b ih => rw [Nat.add_succ, ofNat_succ, ih, ofNat_succ b, add_assoc]
|
||||
|
||||
instance toNatModule [I : Semiring α] : NatModule α :=
|
||||
{ I with
|
||||
zero_nsmul a := by rw [nsmul_eq_natCast_mul, ← ofNat_eq_natCast, zero_mul]
|
||||
one_nsmul a := by rw [nsmul_eq_natCast_mul, ← ofNat_eq_natCast, one_mul]
|
||||
add_nsmul n m a := by rw [nsmul_eq_natCast_mul, ← ofNat_eq_natCast, ofNat_add, right_distrib, ofNat_eq_natCast, ofNat_eq_natCast, ← nsmul_eq_natCast_mul, ← nsmul_eq_natCast_mul]
|
||||
nsmul_zero n := by rw [nsmul_eq_natCast_mul, mul_zero]
|
||||
nsmul_add n a b := by rw [nsmul_eq_natCast_mul, ← ofNat_eq_natCast, left_distrib, ofNat_eq_natCast, ← nsmul_eq_natCast_mul, ← nsmul_eq_natCast_mul] }
|
||||
|
||||
theorem natCast_add (a b : Nat) : ((a + b : Nat) : α) = ((a : α) + (b : α)) := by
|
||||
rw [← ofNat_eq_natCast, ← ofNat_eq_natCast, ofNat_add, ofNat_eq_natCast, ofNat_eq_natCast]
|
||||
theorem natCast_succ (n : Nat) : ((n + 1 : Nat) : α) = ((n : α) + 1) := by
|
||||
rw [natCast_add, natCast_one]
|
||||
|
||||
theorem zero_add (a : α) : 0 + a = a := by
|
||||
rw [add_comm, add_zero]
|
||||
|
||||
theorem add_left_comm (a b c : α) : a + (b + c) = b + (a + c) := by
|
||||
rw [← add_assoc, ← add_assoc, add_comm a]
|
||||
|
||||
theorem ofNat_mul (a b : Nat) : OfNat.ofNat (α := α) (a * b) = OfNat.ofNat a * OfNat.ofNat b := by
|
||||
induction b with
|
||||
| zero => simp [Nat.mul_zero, mul_zero]
|
||||
@@ -191,29 +177,84 @@ theorem natCast_pow (x : Nat) (k : Nat) : ((x ^ k : Nat) : α) = (x : α) ^ k :=
|
||||
next => simp [pow_zero, Nat.pow_zero, natCast_one]
|
||||
next k ih => simp [pow_succ, Nat.pow_succ, natCast_mul, *]
|
||||
|
||||
theorem nsmul_eq_ofNat_mul {α} [Semiring α] {k : Nat} {a : α} : HMul.hMul (α := Nat) k a = OfNat.ofNat k * a := by
|
||||
simp [ofNat_eq_natCast, nsmul_eq_natCast_mul]
|
||||
instance : NatModule α where
|
||||
hMul a x := a * x
|
||||
add_zero := by simp [add_zero]
|
||||
add_assoc := by simp [add_assoc]
|
||||
add_comm := by simp [add_comm]
|
||||
zero_hmul := by simp [natCast_zero, zero_mul]
|
||||
one_hmul := by simp [natCast_one, one_mul]
|
||||
add_hmul := by simp [natCast_add, right_distrib]
|
||||
hmul_zero := by simp [mul_zero]
|
||||
hmul_add := by simp [left_distrib]
|
||||
|
||||
theorem hmul_eq_natCast_mul {α} [Semiring α] {k : Nat} {a : α} : HMul.hMul (α := Nat) k a = (k : α) * a := rfl
|
||||
|
||||
theorem hmul_eq_ofNat_mul {α} [Semiring α] {k : Nat} {a : α} : HMul.hMul (α := Nat) k a = OfNat.ofNat k * a := by
|
||||
simp [ofNat_eq_natCast, hmul_eq_natCast_mul]
|
||||
|
||||
end Semiring
|
||||
|
||||
namespace Ring
|
||||
|
||||
open AddCommMonoid AddCommGroup NatModule IntModule
|
||||
open Semiring hiding add_assoc add_comm
|
||||
open Semiring
|
||||
|
||||
variable {α : Type u} [Ring α]
|
||||
|
||||
theorem add_neg_cancel (a : α) : a + -a = 0 := by
|
||||
rw [add_comm, neg_add_cancel]
|
||||
|
||||
theorem add_left_inj {a b : α} (c : α) : a + c = b + c ↔ a = b :=
|
||||
⟨fun h => by simpa [add_assoc, add_neg_cancel, add_zero] using (congrArg (· + -c) h),
|
||||
fun g => congrArg (· + c) g⟩
|
||||
|
||||
theorem add_right_inj (a b c : α) : a + b = a + c ↔ b = c := by
|
||||
rw [add_comm a b, add_comm a c, add_left_inj]
|
||||
|
||||
theorem neg_zero : (-0 : α) = 0 := by
|
||||
rw [← add_left_inj 0, neg_add_cancel, add_zero]
|
||||
|
||||
theorem neg_neg (a : α) : -(-a) = a := by
|
||||
rw [← add_left_inj (-a), neg_add_cancel, add_neg_cancel]
|
||||
|
||||
theorem neg_eq_zero (a : α) : -a = 0 ↔ a = 0 :=
|
||||
⟨fun h => by
|
||||
replace h := congrArg (-·) h
|
||||
simpa [neg_neg, neg_zero] using h,
|
||||
fun h => by rw [h, neg_zero]⟩
|
||||
|
||||
theorem neg_eq_iff (a b : α) : -a = b ↔ a = -b := by
|
||||
constructor
|
||||
· intro h
|
||||
rw [← neg_neg a, h]
|
||||
· intro h
|
||||
rw [← neg_neg b, h]
|
||||
|
||||
theorem neg_add (a b : α) : -(a + b) = -a + -b := by
|
||||
rw [← add_left_inj (a + b), neg_add_cancel, add_assoc (-a), add_comm a b, ← add_assoc (-b),
|
||||
neg_add_cancel, zero_add, neg_add_cancel]
|
||||
|
||||
theorem neg_sub (a b : α) : -(a - b) = b - a := by
|
||||
rw [sub_eq_add_neg, neg_add, neg_neg, sub_eq_add_neg, add_comm]
|
||||
|
||||
theorem sub_self (a : α) : a - a = 0 := by
|
||||
rw [sub_eq_add_neg, add_neg_cancel]
|
||||
|
||||
theorem sub_eq_iff {a b c : α} : a - b = c ↔ a = c + b := by
|
||||
rw [sub_eq_add_neg]
|
||||
constructor
|
||||
next => intro; subst c; rw [add_assoc, neg_add_cancel, add_zero]
|
||||
next => intro; subst a; rw [add_assoc, add_comm b, neg_add_cancel, add_zero]
|
||||
|
||||
theorem sub_eq_zero_iff {a b : α} : a - b = 0 ↔ a = b := by
|
||||
simp [sub_eq_iff, zero_add]
|
||||
|
||||
theorem intCast_zero : ((0 : Int) : α) = 0 := intCast_ofNat 0
|
||||
theorem intCast_one : ((1 : Int) : α) = 1 := intCast_ofNat 1
|
||||
theorem intCast_neg_one : ((-1 : Int) : α) = -1 := by rw [intCast_neg, intCast_ofNat]
|
||||
theorem intCast_natCast (n : Nat) : ((n : Int) : α) = (n : α) := by
|
||||
erw [intCast_ofNat]
|
||||
rw [ofNat_eq_natCast]
|
||||
|
||||
instance toAddCommGroup [I : Ring α] : AddCommGroup α :=
|
||||
{ I with }
|
||||
|
||||
theorem intCast_zero : ((0 : Int) : α) = 0 := by
|
||||
rw [intCast_ofNat 0]
|
||||
theorem intCast_one : ((1 : Int) : α) = 1 := intCast_ofNat 1
|
||||
theorem intCast_neg_one : ((-1 : Int) : α) = -1 := by rw [intCast_neg, intCast_ofNat]
|
||||
theorem intCast_natCast_add_one (n : Nat) : ((n + 1 : Int) : α) = (n : α) + 1 := by
|
||||
rw [← Int.natCast_add_one, intCast_natCast, natCast_add, ofNat_eq_natCast]
|
||||
theorem intCast_negSucc (n : Nat) : ((-(n + 1) : Int) : α) = -((n : α) + 1) := by
|
||||
@@ -232,8 +273,7 @@ theorem intCast_nat_sub {x y : Nat} (h : x ≥ y) : (((x - y : Nat) : Int) : α)
|
||||
rw [this, intCast_natCast_add_one]
|
||||
specialize ih (by omega)
|
||||
rw [intCast_natCast] at ih
|
||||
rw [ih, natCast_succ, sub_eq_add_neg, sub_eq_add_neg, add_assoc,
|
||||
AddCommMonoid.add_comm _ 1, ← add_assoc]
|
||||
rw [ih, natCast_succ, sub_eq_add_neg, sub_eq_add_neg, add_assoc, add_comm _ 1, ← add_assoc]
|
||||
theorem intCast_add (x y : Int) : ((x + y : Int) : α) = ((x : α) + (y : α)) :=
|
||||
match x, y with
|
||||
| (x : Nat), (y : Nat) => by
|
||||
@@ -283,36 +323,19 @@ theorem neg_mul (a b : α) : (-a) * b = -(a * b) := by
|
||||
theorem mul_neg (a b : α) : a * (-b) = -(a * b) := by
|
||||
rw [neg_eq_mul_neg_one b, neg_eq_mul_neg_one (a * b), mul_assoc]
|
||||
|
||||
attribute [local instance] Ring.zsmul in
|
||||
theorem zsmul_eq_intCast_mul {k : Int} {a : α} : (HMul.hMul (α := Int) (γ := α) k a : α) = (k : α) * a := by
|
||||
match k with
|
||||
| (k : Nat) =>
|
||||
rw [intCast_natCast, zsmul_natCast_eq_nsmul, nsmul_eq_natCast_mul]
|
||||
| -(k + 1 : Nat) =>
|
||||
rw [intCast_neg, neg_mul, neg_zsmul, intCast_natCast, zsmul_natCast_eq_nsmul, nsmul_eq_natCast_mul]
|
||||
|
||||
instance toIntModule [I : Ring α] : IntModule α :=
|
||||
{ I, Semiring.toNatModule (α := α) with
|
||||
zero_zsmul a := by rw [← Int.natCast_zero, zsmul_natCast_eq_nsmul, zero_nsmul]
|
||||
one_zsmul a := by rw [← Int.natCast_one, zsmul_natCast_eq_nsmul, one_nsmul]
|
||||
add_zsmul n m a := by rw [zsmul_eq_intCast_mul, intCast_add, right_distrib, zsmul_eq_intCast_mul, zsmul_eq_intCast_mul]
|
||||
zsmul_zero n := by rw [zsmul_eq_intCast_mul, mul_zero]
|
||||
zsmul_add n a b := by
|
||||
rw [zsmul_eq_intCast_mul, left_distrib, zsmul_eq_intCast_mul, zsmul_eq_intCast_mul] }
|
||||
|
||||
private theorem intCast_mul_aux (x y : Nat) : ((x * y : Int) : α) = ((x : α) * (y : α)) := by
|
||||
theorem intCast_nat_mul (x y : Nat) : ((x * y : Int) : α) = ((x : α) * (y : α)) := by
|
||||
rw [Int.ofNat_mul_ofNat, intCast_natCast, natCast_mul]
|
||||
|
||||
theorem intCast_mul (x y : Int) : ((x * y : Int) : α) = ((x : α) * (y : α)) :=
|
||||
match x, y with
|
||||
| (x : Nat), (y : Nat) => by
|
||||
rw [intCast_mul_aux, intCast_natCast, intCast_natCast]
|
||||
rw [intCast_nat_mul, intCast_natCast, intCast_natCast]
|
||||
| (x : Nat), (-(y + 1 : Nat)) => by
|
||||
rw [Int.mul_neg, intCast_neg, intCast_mul_aux, intCast_neg, mul_neg, intCast_natCast, intCast_natCast]
|
||||
rw [Int.mul_neg, intCast_neg, intCast_nat_mul, intCast_neg, mul_neg, intCast_natCast, intCast_natCast]
|
||||
| (-(x + 1 : Nat)), (y : Nat) => by
|
||||
rw [Int.neg_mul, intCast_neg, intCast_mul_aux, intCast_neg, neg_mul, intCast_natCast, intCast_natCast]
|
||||
rw [Int.neg_mul, intCast_neg, intCast_nat_mul, intCast_neg, neg_mul, intCast_natCast, intCast_natCast]
|
||||
| (-(x + 1 : Nat)), (-(y + 1 : Nat)) => by
|
||||
rw [Int.neg_mul_neg, intCast_neg, intCast_neg, neg_mul, mul_neg, neg_neg, intCast_mul_aux,
|
||||
rw [Int.neg_mul_neg, intCast_neg, intCast_neg, neg_mul, mul_neg, neg_neg, intCast_nat_mul,
|
||||
intCast_natCast, intCast_natCast]
|
||||
|
||||
theorem intCast_pow (x : Int) (k : Nat) : ((x ^ k : Int) : α) = (x : α) ^ k := by
|
||||
@@ -320,8 +343,27 @@ theorem intCast_pow (x : Int) (k : Nat) : ((x ^ k : Int) : α) = (x : α) ^ k :=
|
||||
next => simp [pow_zero, Int.pow_zero, intCast_one]
|
||||
next k ih => simp [pow_succ, Int.pow_succ, intCast_mul, *]
|
||||
|
||||
instance : IntModule α where
|
||||
hmulInt := ⟨fun a x => a * x⟩
|
||||
hmulNat := ⟨fun a x => a * x⟩
|
||||
hmul_nat n x := by
|
||||
change ((n : Int) : α) * x = (n : α) * x
|
||||
rw [intCast_natCast]
|
||||
add_zero := by simp [add_zero]
|
||||
add_assoc := by simp [add_assoc]
|
||||
add_comm := by simp [add_comm]
|
||||
zero_hmul := by simp [intCast_zero, zero_mul]
|
||||
one_hmul := by simp [intCast_one, one_mul]
|
||||
add_hmul := by simp [intCast_add, right_distrib]
|
||||
hmul_zero := by simp [mul_zero]
|
||||
hmul_add := by simp [left_distrib]
|
||||
neg_add_cancel := by simp [neg_add_cancel]
|
||||
sub_eq_add_neg := by simp [sub_eq_add_neg]
|
||||
|
||||
theorem hmul_eq_intCast_mul {α} [Ring α] {k : Int} {a : α} : HMul.hMul (α := Int) k a = (k : α) * a := rfl
|
||||
|
||||
-- Verify that the diamond from `Ring` to `NatModule` via either `Semiring` or `IntModule` is defeq.
|
||||
example [Ring R] : (Semiring.toNatModule : NatModule R) = IntModule.toNatModule (M := R) := rfl
|
||||
example [Ring R] : (Semiring.instNatModule : NatModule R) = (IntModule.toNatModule R) := rfl
|
||||
|
||||
end Ring
|
||||
|
||||
@@ -336,9 +378,7 @@ theorem mul_left_comm (a b c : α) : a * (b * c) = b * (a * c) := by
|
||||
|
||||
end CommSemiring
|
||||
|
||||
open Semiring hiding add_comm add_assoc add_zero
|
||||
open Ring hiding neg_add_cancel
|
||||
open CommSemiring CommRing
|
||||
open Semiring Ring CommSemiring CommRing
|
||||
|
||||
/--
|
||||
A ring `α` has characteristic `p` if `OfNat.ofNat x = 0` iff `x % p = 0`.
|
||||
@@ -410,8 +450,6 @@ end Semiring
|
||||
|
||||
section Ring
|
||||
|
||||
open AddCommMonoid AddCommGroup
|
||||
|
||||
variable (p) {α : Type u} [Ring α] [IsCharP α p]
|
||||
|
||||
private theorem mk'_aux {x y : Nat} (p : Nat) (h : y ≤ x) :
|
||||
@@ -487,8 +525,7 @@ theorem intCast_ext_iff {x y : Int} : (x : α) = (y : α) ↔ x % p = y % p := b
|
||||
have : ((x - y : Int) : α) = 0 :=
|
||||
(intCast_eq_zero_iff p _).mpr (by rw [Int.sub_emod, h, Int.sub_self, Int.zero_emod])
|
||||
replace this := congrArg (· + (y : α)) this
|
||||
simpa [intCast_sub, zero_add, AddCommGroup.sub_eq_add_neg, add_assoc,
|
||||
neg_add_cancel, add_zero] using this
|
||||
simpa [intCast_sub, zero_add, sub_eq_add_neg, add_assoc, neg_add_cancel, add_zero] using this
|
||||
|
||||
theorem intCast_emod (x : Int) : ((x % p : Int) : α) = (x : α) := by
|
||||
rw [intCast_ext_iff p, Int.emod_emod]
|
||||
@@ -497,8 +534,6 @@ end Ring
|
||||
|
||||
end IsCharP
|
||||
|
||||
open AddCommGroup
|
||||
|
||||
theorem no_int_zero_divisors {α : Type u} [IntModule α] [NoNatZeroDivisors α] {k : Int} {a : α}
|
||||
: k ≠ 0 → k * a = 0 → a = 0 := by
|
||||
match k with
|
||||
@@ -506,15 +541,15 @@ theorem no_int_zero_divisors {α : Type u} [IntModule α] [NoNatZeroDivisors α]
|
||||
simp only [ne_eq, Int.natCast_eq_zero]
|
||||
intro h₁ h₂
|
||||
replace h₁ : k ≠ 0 := by intro h; simp [h] at h₁
|
||||
rw [IntModule.zsmul_natCast_eq_nsmul] at h₂
|
||||
rw [IntModule.hmul_nat] at h₂
|
||||
exact NoNatZeroDivisors.eq_zero_of_mul_eq_zero h₁ h₂
|
||||
| -(k+1 : Nat) =>
|
||||
rw [IntModule.neg_zsmul]
|
||||
rw [IntModule.neg_hmul]
|
||||
intro _ h
|
||||
replace h := congrArg (-·) h
|
||||
dsimp only at h
|
||||
rw [neg_neg, neg_zero] at h
|
||||
rw [IntModule.zsmul_natCast_eq_nsmul] at h
|
||||
rw [IntModule.neg_neg, IntModule.neg_zero] at h
|
||||
rw [IntModule.hmul_nat] at h
|
||||
exact NoNatZeroDivisors.eq_zero_of_mul_eq_zero (Nat.succ_ne_zero _) h
|
||||
|
||||
end Lean.Grind
|
||||
|
||||
@@ -141,7 +141,7 @@ def Q.ind {β : Q α → Prop} (mk : ∀ (a : α × α), β (Q.mk a)) (q : Q α)
|
||||
exact ⟨k, h.symm⟩)
|
||||
|
||||
attribute [local simp]
|
||||
Quot.liftOn Semiring.add_zero AddCommMonoid.zero_add Semiring.mul_one Semiring.one_mul
|
||||
Quot.liftOn Semiring.add_zero Semiring.zero_add Semiring.mul_one Semiring.one_mul
|
||||
Semiring.natCast_zero Semiring.natCast_one Semiring.mul_zero Semiring.zero_mul
|
||||
|
||||
theorem neg_add_cancel (a : Q α) : add (neg a) a = natCast 0 := by
|
||||
@@ -236,28 +236,7 @@ private theorem pow_zero (a : Q α) : hPow a 0 = natCast 1 := rfl
|
||||
|
||||
private theorem pow_succ (a : Q α) (n : Nat) : hPow a (n+1) = mul (hPow a n) a := rfl
|
||||
|
||||
def nsmul (n : Nat) (a : Q α) : Q α :=
|
||||
mul (natCast n) a
|
||||
|
||||
def zsmul (i : Int) (a : Q α) : Q α :=
|
||||
mul (intCast i) a
|
||||
|
||||
theorem neg_zsmul (i : Int) (a : Q α) : zsmul (-i) a = neg (zsmul i a) := by
|
||||
induction a using Quot.ind
|
||||
next a =>
|
||||
cases a; simp [zsmul]
|
||||
split <;> rename_i h₁
|
||||
· split <;> rename_i h₂
|
||||
· omega
|
||||
· simp
|
||||
· split <;> rename_i h₂
|
||||
· simp
|
||||
· have : i = 0 := by omega
|
||||
simp [this]
|
||||
|
||||
def ofSemiring : Ring (Q α) := {
|
||||
nsmul := ⟨nsmul⟩
|
||||
zsmul := ⟨zsmul⟩
|
||||
ofNat := fun n => ⟨natCast n⟩
|
||||
natCast := ⟨natCast⟩
|
||||
intCast := ⟨intCast⟩
|
||||
@@ -266,7 +245,7 @@ def ofSemiring : Ring (Q α) := {
|
||||
neg_add_cancel, sub_eq_add_neg
|
||||
mul_one, one_mul, zero_mul, mul_zero, mul_assoc,
|
||||
left_distrib, right_distrib, pow_zero, pow_succ,
|
||||
intCast_neg, ofNat_succ, neg_zsmul
|
||||
intCast_neg, ofNat_succ
|
||||
}
|
||||
|
||||
attribute [instance] ofSemiring
|
||||
@@ -349,8 +328,7 @@ instance [Semiring α] [AddRightCancel α] [NoNatZeroDivisors α] : NoNatZeroDiv
|
||||
simp [r] at h₂
|
||||
rcases h₂ with ⟨k', h₂⟩
|
||||
replace h₂ := AddRightCancel.add_right_cancel _ _ _ h₂
|
||||
simp only [← Semiring.left_distrib] at h₂
|
||||
simp only [← Semiring.nsmul_eq_natCast_mul] at h₂
|
||||
simp [← Semiring.left_distrib] at h₂
|
||||
replace h₂ := NoNatZeroDivisors.no_nat_zero_divisors k (a₁ + b₂) (a₂ + b₁) h₁ h₂
|
||||
apply Quot.sound; simp [r]; exists 0; simp [h₂]
|
||||
|
||||
@@ -422,7 +400,7 @@ instance [Preorder α] [OrderedAdd α] : Preorder (OfSemiring.Q α) where
|
||||
|
||||
@[local simp] private theorem mk_pos [Preorder α] [OrderedAdd α] {a₁ a₂ : α} :
|
||||
0 < Q.mk (a₁, a₂) ↔ a₂ < a₁ := by
|
||||
simp [← toQ_ofNat, toQ, mk_lt_mk, AddCommMonoid.zero_add]
|
||||
simp [← toQ_ofNat, toQ, mk_lt_mk, Semiring.zero_add]
|
||||
|
||||
@[local simp]
|
||||
theorem toQ_le [Preorder α] [OrderedAdd α] {a b : α} : toQ a ≤ toQ b ↔ a ≤ b := by
|
||||
@@ -525,16 +503,6 @@ def ofCommSemiring : CommRing (OfSemiring.Q α) :=
|
||||
|
||||
attribute [instance] ofCommSemiring
|
||||
|
||||
/-
|
||||
Remark: `↑a` is notation for `OfSemiring.toQ a`.
|
||||
We want to hide `OfSemiring.toQ` applications in the diagnostic information produced by
|
||||
the `ring` procedure in `grind`.
|
||||
-/
|
||||
@[app_unexpander OfSemiring.toQ]
|
||||
meta def toQUnexpander : PrettyPrinter.Unexpander := fun stx => do
|
||||
match stx with
|
||||
| `($_ $a:term) => `(↑$a)
|
||||
| _ => throw ()
|
||||
|
||||
end OfCommSemiring
|
||||
|
||||
end Lean.Grind.CommRing
|
||||
|
||||
@@ -57,10 +57,10 @@ theorem inv_inv (a : α) : a⁻¹⁻¹ = a := by
|
||||
theorem inv_neg (a : α) : (-a)⁻¹ = -a⁻¹ := by
|
||||
by_cases h : a = 0
|
||||
· subst h
|
||||
simp [Field.inv_zero, AddCommGroup.neg_zero]
|
||||
simp [Field.inv_zero, Ring.neg_zero]
|
||||
· symm
|
||||
apply eq_inv_of_mul_eq_one
|
||||
simp [Ring.neg_mul, Ring.mul_neg, AddCommGroup.neg_neg, Field.inv_mul_cancel h]
|
||||
simp [Ring.neg_mul, Ring.mul_neg, Ring.neg_neg, Field.inv_mul_cancel h]
|
||||
|
||||
theorem inv_eq_zero_iff {a : α} : a⁻¹ = 0 ↔ a = 0 := by
|
||||
constructor
|
||||
@@ -80,45 +80,6 @@ theorem inv_eq_zero_iff {a : α} : a⁻¹ = 0 ↔ a = 0 := by
|
||||
theorem zero_eq_inv_iff {a : α} : 0 = a⁻¹ ↔ 0 = a := by
|
||||
rw [eq_comm, inv_eq_zero_iff, eq_comm]
|
||||
|
||||
theorem of_mul_eq_zero {a b : α} : a*b = 0 → a = 0 ∨ b = 0 := by
|
||||
cases (Classical.em (a = 0)); simp [*, Semiring.zero_mul]
|
||||
cases (Classical.em (b = 0)); simp [*, Semiring.mul_zero]
|
||||
next h₁ h₂ =>
|
||||
replace h₁ := Field.mul_inv_cancel h₁
|
||||
replace h₂ := Field.mul_inv_cancel h₂
|
||||
intro h
|
||||
replace h := congrArg (· * b⁻¹ * a⁻¹) h; simp [Semiring.zero_mul] at h
|
||||
rw [Semiring.mul_assoc, Semiring.mul_assoc, ← Semiring.mul_assoc b, h₂, Semiring.one_mul, h₁] at h
|
||||
have := Field.zero_ne_one (α := α)
|
||||
simp [h] at this
|
||||
|
||||
theorem mul_inv (a b : α) : (a*b)⁻¹ = a⁻¹*b⁻¹ := by
|
||||
cases (Classical.em (a = 0)); simp [*, Semiring.zero_mul, Field.inv_zero]
|
||||
cases (Classical.em (b = 0)); simp [*, Semiring.mul_zero, Field.inv_zero]
|
||||
cases (Classical.em (a*b = 0)); simp [*, Field.inv_zero]
|
||||
next h => cases (of_mul_eq_zero h) <;> contradiction
|
||||
next h₁ h₂ h₃ =>
|
||||
replace h₁ := Field.inv_mul_cancel h₁
|
||||
replace h₂ := Field.inv_mul_cancel h₂
|
||||
replace h₃ := Field.mul_inv_cancel h₃
|
||||
replace h₃ := congrArg (b⁻¹*a⁻¹* ·) h₃; simp at h₃
|
||||
rw [Semiring.mul_assoc, Semiring.mul_assoc, ← Semiring.mul_assoc (a⁻¹), h₁, Semiring.one_mul,
|
||||
← Semiring.mul_assoc, h₂, Semiring.one_mul, Semiring.mul_one, CommRing.mul_comm (b⁻¹)] at h₃
|
||||
assumption
|
||||
|
||||
theorem of_pow_eq_zero (a : α) (n : Nat) : a^n = 0 → a = 0 := by
|
||||
induction n
|
||||
next => simp [Semiring.pow_zero]; intro h; have := zero_ne_one (α := α); exfalso; exact this h.symm
|
||||
next n ih =>
|
||||
simp [Semiring.pow_succ]; intro h
|
||||
apply Classical.byContradiction
|
||||
intro hne
|
||||
have := Field.mul_inv_cancel hne
|
||||
replace h := congrArg (· * a⁻¹) h; simp at h
|
||||
rw [Semiring.mul_assoc, this, Semiring.mul_one, Semiring.zero_mul] at h
|
||||
have := ih h
|
||||
contradiction
|
||||
|
||||
instance [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
|
||||
intro a b h w
|
||||
have := IsCharP.natCast_eq_zero_iff (α := α) 0 a
|
||||
@@ -129,7 +90,7 @@ instance [IsCharP α 0] : NoNatZeroDivisors α := NoNatZeroDivisors.mk' <| by
|
||||
rw [Semiring.ofNat_eq_natCast] at w
|
||||
replace w := congrArg (fun x => x * b⁻¹) w
|
||||
dsimp only [] at w
|
||||
rw [Semiring.nsmul_eq_ofNat_mul, Semiring.mul_assoc, Field.mul_inv_cancel h, Semiring.mul_one,
|
||||
rw [Semiring.hmul_eq_ofNat_mul, Semiring.mul_assoc, Field.mul_inv_cancel h, Semiring.mul_one,
|
||||
Semiring.natCast_zero, Semiring.zero_mul, Semiring.ofNat_eq_natCast] at w
|
||||
contradiction
|
||||
|
||||
|
||||
@@ -80,9 +80,7 @@ end Ring.OfSemiring
|
||||
|
||||
namespace CommRing
|
||||
attribute [local instance] Semiring.natCast Ring.intCast
|
||||
open AddCommMonoid AddCommGroup
|
||||
open Semiring hiding add_zero add_comm add_assoc
|
||||
open Ring CommSemiring
|
||||
open Semiring Ring CommSemiring
|
||||
|
||||
inductive Poly.NonnegCoeffs : Poly → Prop
|
||||
| num (c : Int) : c ≥ 0 → NonnegCoeffs (.num c)
|
||||
|
||||
@@ -13,7 +13,7 @@ public import Init.Data.RArray
|
||||
public import Init.Grind.Ring.Basic
|
||||
public import Init.Grind.Ring.Field
|
||||
public import Init.Grind.Ordered.Ring
|
||||
public import Init.GrindInstances.Ring.Int
|
||||
|
||||
public section
|
||||
|
||||
namespace Lean.Grind
|
||||
@@ -97,17 +97,6 @@ def Mon.denote {α} [Semiring α] (ctx : Context α) : Mon → α
|
||||
| unit => 1
|
||||
| .mult p m => p.denote ctx * denote ctx m
|
||||
|
||||
@[expose]
|
||||
def Mon.denote' {α} [Semiring α] (ctx : Context α) (m : Mon) : α :=
|
||||
match m with
|
||||
| .unit => 1
|
||||
| .mult pw m => go m (pw.denote ctx)
|
||||
where
|
||||
go (m : Mon) (acc : α) : α :=
|
||||
match m with
|
||||
| .unit => acc
|
||||
| .mult pw m => go m (acc * (pw.denote ctx))
|
||||
|
||||
@[expose]
|
||||
def Mon.ofVar (x : Var) : Mon :=
|
||||
.mult { x, k := 1 } .unit
|
||||
@@ -245,25 +234,7 @@ instance : LawfulBEq Poly where
|
||||
def Poly.denote [Ring α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => Int.cast k
|
||||
| .add k m p => HMul.hMul (α := Int) k (m.denote ctx) + denote ctx p
|
||||
|
||||
@[expose]
|
||||
def Poly.denote' [Ring α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => Int.cast k
|
||||
| .add k m p => go p (denoteTerm k m)
|
||||
where
|
||||
denoteTerm (k : Int) (m : Mon) : α :=
|
||||
bif k == 1 then
|
||||
m.denote' ctx
|
||||
else
|
||||
HMul.hMul (α := Int) k (m.denote' ctx)
|
||||
|
||||
go (p : Poly) (acc : α) : α :=
|
||||
match p with
|
||||
| .num 0 => acc
|
||||
| .num k => acc + Int.cast k
|
||||
| .add k m p => go p (acc + denoteTerm k m)
|
||||
| .add k m p => Int.cast k * m.denote ctx + denote ctx p
|
||||
|
||||
@[expose]
|
||||
def Poly.ofMon (m : Mon) : Poly :=
|
||||
@@ -395,9 +366,7 @@ def Expr.toPoly : Expr → Poly
|
||||
| .neg a => a.toPoly.mulConst (-1)
|
||||
| .sub a b => a.toPoly.combine (b.toPoly.mulConst (-1))
|
||||
| .pow a k =>
|
||||
bif k == 0 then
|
||||
.num 1
|
||||
else match a with
|
||||
match a with
|
||||
| .num n => .num (n^k)
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => a.toPoly.pow k
|
||||
@@ -538,9 +507,7 @@ where
|
||||
| .neg a => (go a).mulConstC (-1) c
|
||||
| .sub a b => (go a).combineC ((go b).mulConstC (-1) c) c
|
||||
| .pow a k =>
|
||||
bif k == 0 then
|
||||
.num 1
|
||||
else match a with
|
||||
match a with
|
||||
| .num n => .num ((n^k) % c)
|
||||
| .var x => Poly.ofMon (.mult {x, k} .unit)
|
||||
| _ => (go a).powC k c
|
||||
@@ -598,10 +565,7 @@ def NullCert.toPolyC (nc : NullCert) (c : Nat) : Poly :=
|
||||
Theorems for justifying the procedure for commutative rings in `grind`.
|
||||
-/
|
||||
|
||||
open AddCommMonoid AddCommGroup NatModule IntModule
|
||||
open Semiring hiding add_zero add_comm add_assoc
|
||||
open Ring hiding sub_eq_add_neg
|
||||
open CommSemiring
|
||||
open Semiring Ring CommSemiring
|
||||
|
||||
theorem denoteInt_eq {α} [CommRing α] (k : Int) : denoteInt (α := α) k = k := by
|
||||
simp [denoteInt, cond_eq_if] <;> split
|
||||
@@ -612,14 +576,6 @@ theorem Power.denote_eq {α} [Semiring α] (ctx : Context α) (p : Power)
|
||||
: p.denote ctx = p.x.denote ctx ^ p.k := by
|
||||
cases p <;> simp [Power.denote] <;> split <;> simp [pow_zero, pow_succ, one_mul]
|
||||
|
||||
theorem Mon.denote'_eq_denote {α} [Semiring α] (ctx : Context α) (m : Mon) : m.denote' ctx = m.denote ctx := by
|
||||
cases m <;> simp [denote', denote]
|
||||
next pw m =>
|
||||
generalize pw.denote ctx = acc
|
||||
fun_induction denote'.go
|
||||
next => simp [denote, Semiring.mul_one]
|
||||
next acc pw m ih => simp [ih, denote, Semiring.mul_assoc]
|
||||
|
||||
theorem Mon.denote_ofVar {α} [Semiring α] (ctx : Context α) (x : Var)
|
||||
: denote ctx (ofVar x) = x.denote ctx := by
|
||||
simp [denote, ofVar, Power.denote_eq, pow_succ, pow_zero, one_mul, mul_one]
|
||||
@@ -702,19 +658,9 @@ theorem Mon.eq_of_revlex {m₁ m₂ : Mon} : revlex m₁ m₂ = .eq → m₁ = m
|
||||
theorem Mon.eq_of_grevlex {m₁ m₂ : Mon} : grevlex m₁ m₂ = .eq → m₁ = m₂ := by
|
||||
simp [grevlex]; intro; apply eq_of_revlex
|
||||
|
||||
theorem Poly.denoteTerm_eq {α} [Ring α] (ctx : Context α) (k : Int) (m : Mon) : denote'.denoteTerm ctx k m = k * m.denote ctx := by
|
||||
simp [denote'.denoteTerm, Mon.denote'_eq_denote, cond_eq_if, zsmul_eq_intCast_mul]; intro; subst k; rw [Ring.intCast_one, Semiring.one_mul]
|
||||
|
||||
theorem Poly.denote'_eq_denote {α} [Ring α] (ctx : Context α) (p : Poly) : p.denote' ctx = p.denote ctx := by
|
||||
cases p <;> simp [denote', denote, denoteTerm_eq, zsmul_eq_intCast_mul]
|
||||
next k m p =>
|
||||
generalize k * m.denote ctx = acc
|
||||
fun_induction denote'.go <;> simp [denote, *, Ring.intCast_zero, Semiring.add_zero, denoteTerm_eq]
|
||||
next ih => simp [denoteTerm_eq] at ih; simp [ih, Semiring.add_assoc, zsmul_eq_intCast_mul]
|
||||
|
||||
theorem Poly.denote_ofMon {α} [CommRing α] (ctx : Context α) (m : Mon)
|
||||
: denote ctx (ofMon m) = m.denote ctx := by
|
||||
simp [ofMon, denote, intCast_one, intCast_zero, one_mul, add_zero, zsmul_eq_intCast_mul]
|
||||
simp [ofMon, denote, intCast_one, intCast_zero, one_mul, add_zero]
|
||||
|
||||
theorem Poly.denote_ofVar {α} [CommRing α] (ctx : Context α) (x : Var)
|
||||
: denote ctx (ofVar x) = x.denote ctx := by
|
||||
@@ -737,7 +683,7 @@ theorem Poly.denote_insert {α} [CommRing α] (ctx : Context α) (k : Int) (m :
|
||||
next h =>
|
||||
simp at h <;> simp [*, Mon.denote, denote_addConst, mul_one, add_comm]
|
||||
next =>
|
||||
fun_induction insert.go <;> simp_all +zetaDelta [denote, zsmul_eq_intCast_mul]
|
||||
fun_induction insert.go <;> simp_all +zetaDelta [denote]
|
||||
next h₁ h₂ =>
|
||||
rw [← add_assoc, Mon.eq_of_grevlex h₁, ← right_distrib, ← intCast_add, h₂, intCast_zero, zero_mul, zero_add]
|
||||
next h₁ _ =>
|
||||
@@ -759,7 +705,7 @@ theorem Poly.denote_mulConst {α} [CommRing α] (ctx : Context α) (k : Int) (p
|
||||
split <;> try simp [*, intCast_one, one_mul]
|
||||
fun_induction mulConst.go <;> simp [denote, *]
|
||||
next => rw [intCast_mul]
|
||||
next => rw [left_distrib, ← zsmul_eq_intCast_mul, ← zsmul_eq_intCast_mul, mul_zsmul]
|
||||
next => rw [intCast_mul, left_distrib, mul_assoc]
|
||||
|
||||
theorem Poly.denote_mulMon {α} [CommRing α] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMon k m p).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
@@ -770,7 +716,7 @@ theorem Poly.denote_mulMon {α} [CommRing α] (ctx : Context α) (k : Int) (m :
|
||||
next h =>
|
||||
simp at h; simp [*, Mon.denote, mul_one, denote_mulConst]
|
||||
next =>
|
||||
fun_induction mulMon.go <;> simp [denote, zsmul_eq_intCast_mul, *]
|
||||
fun_induction mulMon.go <;> simp [denote, *]
|
||||
next h => simp +zetaDelta at h; simp [*, intCast_zero, mul_zero]
|
||||
next => simp [intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
|
||||
next => simp [Mon.denote_mul, intCast_mul, left_distrib, mul_left_comm, mul_assoc]
|
||||
@@ -779,7 +725,7 @@ theorem Poly.denote_combine {α} [CommRing α] (ctx : Context α) (p₁ p₂ : P
|
||||
: (combine p₁ p₂).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combine; generalize hugeFuel = fuel
|
||||
fun_induction combine.go
|
||||
<;> simp [*, denote_concat, denote_addConst, denote, intCast_add, add_comm, add_left_comm, add_assoc, zsmul_eq_intCast_mul]
|
||||
<;> simp [*, denote_concat, denote_addConst, denote, intCast_add, add_comm, add_left_comm, add_assoc]
|
||||
case case5 hg _ h _ =>
|
||||
simp +zetaDelta at h
|
||||
rw [← add_assoc, Mon.eq_of_grevlex hg, ← right_distrib, ← intCast_add, h, intCast_zero, zero_mul, zero_add]
|
||||
@@ -790,7 +736,7 @@ theorem Poly.denote_combine {α} [CommRing α] (ctx : Context α) (p₁ p₂ : P
|
||||
theorem Poly.denote_mul_go {α} [CommRing α] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mul.go p₂ p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mul.go
|
||||
<;> simp [denote_combine, denote_mulConst, denote, *, right_distrib, denote_mulMon, add_assoc, zsmul_eq_intCast_mul]
|
||||
<;> simp [denote_combine, denote_mulConst, denote, *, right_distrib, denote_mulMon, add_assoc]
|
||||
|
||||
theorem Poly.denote_mul {α} [CommRing α] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mul p₁ p₂).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
@@ -809,7 +755,6 @@ theorem Expr.denote_toPoly {α} [CommRing α] (ctx : Context α) (e : Expr)
|
||||
<;> simp [denote, Poly.denote, Poly.denote_ofVar, Poly.denote_combine,
|
||||
Poly.denote_mul, Poly.denote_mulConst, Poly.denote_pow, intCast_pow, intCast_neg, intCast_one,
|
||||
neg_mul, one_mul, sub_eq_add_neg, denoteInt_eq, *]
|
||||
next a k h => simp at h; simp [h, Semiring.pow_zero]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
theorem Expr.eq_of_toPoly_eq {α} [CommRing α] (ctx : Context α) (a b : Expr) (h : a.toPoly == b.toPoly) : a.denote ctx = b.denote ctx := by
|
||||
@@ -863,7 +808,7 @@ theorem NullCert.eq_nzdiv {α} [CommRing α] [NoNatZeroDivisors α] (ctx : Conte
|
||||
apply eqsImplies_helper
|
||||
intro h₃
|
||||
replace h₂ := congrArg (Poly.denote ctx) h₂
|
||||
simp [Expr.denote_toPoly, Poly.denote_mulConst, denote_toPoly, h₃, Expr.denote, ← zsmul_eq_intCast_mul] at h₂
|
||||
simp [Expr.denote_toPoly, Poly.denote_mulConst, denote_toPoly, h₃, Expr.denote] at h₂
|
||||
replace h₂ := no_int_zero_divisors h₁ h₂
|
||||
rw [sub_eq_zero_iff] at h₂
|
||||
assumption
|
||||
@@ -905,7 +850,7 @@ theorem Poly.denote_insertC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
rw [← IsCharP.intCast_emod (p := c)]
|
||||
simp +zetaDelta [*, intCast_zero, zero_mul, zero_add]
|
||||
next =>
|
||||
fun_induction insertC.go <;> simp_all +zetaDelta [denote, zsmul_eq_intCast_mul]
|
||||
fun_induction insertC.go <;> simp_all +zetaDelta [denote]
|
||||
next h₁ _ h₂ => rw [IsCharP.intCast_emod]
|
||||
next h₁ _ h₂ =>
|
||||
rw [← add_assoc, Mon.eq_of_grevlex h₁, ← right_distrib, ← intCast_add, ← IsCharP.intCast_emod (p := c), h₂,
|
||||
@@ -931,10 +876,10 @@ theorem Poly.denote_mulConstC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
next => rw [intCast_mul]
|
||||
next h _ =>
|
||||
simp +zetaDelta at h
|
||||
rw [left_distrib, zsmul_eq_intCast_mul, ← mul_assoc, ← intCast_mul, ← IsCharP.intCast_emod (x := k * _) (p := c),
|
||||
rw [left_distrib, ← mul_assoc, ← intCast_mul, ← IsCharP.intCast_emod (x := k * _) (p := c),
|
||||
h, intCast_zero, zero_mul, zero_add]
|
||||
next h _ =>
|
||||
simp +zetaDelta [IsCharP.intCast_emod, intCast_mul, mul_assoc, left_distrib, zsmul_eq_intCast_mul]
|
||||
simp +zetaDelta [IsCharP.intCast_emod, intCast_mul, mul_assoc, left_distrib]
|
||||
|
||||
theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (k : Int) (m : Mon) (p : Poly)
|
||||
: (mulMonC k m p c).denote ctx = k * m.denote ctx * p.denote ctx := by
|
||||
@@ -953,23 +898,23 @@ theorem Poly.denote_mulMonC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
rw [mul_assoc, mul_left_comm, ← intCast_mul, ← IsCharP.intCast_emod (x := k * _) (p := c), h]
|
||||
simp [intCast_zero, mul_zero]
|
||||
next h =>
|
||||
simp +zetaDelta [IsCharP.intCast_emod, intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc, zsmul_eq_intCast_mul]
|
||||
simp +zetaDelta [IsCharP.intCast_emod, intCast_mul, intCast_zero, add_zero, mul_comm, mul_left_comm, mul_assoc]
|
||||
next h _ =>
|
||||
simp +zetaDelta at h; simp [*, left_distrib, zsmul_eq_intCast_mul]
|
||||
simp +zetaDelta at h; simp [*, left_distrib]
|
||||
rw [mul_left_comm]
|
||||
conv => rhs; rw [← mul_assoc, ← mul_assoc, ← intCast_mul, ← IsCharP.intCast_emod (p := c)]
|
||||
rw [Int.mul_comm] at h
|
||||
simp [h, intCast_zero, zero_mul, zero_add]
|
||||
next h _ =>
|
||||
simp +zetaDelta [*, IsCharP.intCast_emod, Mon.denote_mul, intCast_mul, left_distrib,
|
||||
mul_left_comm, mul_assoc, zsmul_eq_intCast_mul]
|
||||
mul_left_comm, mul_assoc]
|
||||
|
||||
theorem Poly.denote_combineC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (combineC p₁ p₂ c).denote ctx = p₁.denote ctx + p₂.denote ctx := by
|
||||
unfold combineC; generalize hugeFuel = fuel
|
||||
fun_induction combineC.go
|
||||
<;> simp [*, denote_concat, denote_addConstC, denote, intCast_add,
|
||||
add_comm, add_left_comm, add_assoc, IsCharP.intCast_emod, zsmul_eq_intCast_mul]
|
||||
add_comm, add_left_comm, add_assoc, IsCharP.intCast_emod]
|
||||
next hg _ h _ =>
|
||||
simp +zetaDelta at h
|
||||
rw [← add_assoc, Mon.eq_of_grevlex hg, ← right_distrib, ← intCast_add,
|
||||
@@ -982,7 +927,7 @@ theorem Poly.denote_combineC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
theorem Poly.denote_mulC_go {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ acc : Poly)
|
||||
: (mulC.go p₂ c p₁ acc).denote ctx = acc.denote ctx + p₁.denote ctx * p₂.denote ctx := by
|
||||
fun_induction mulC.go
|
||||
<;> simp [denote_combineC, denote_mulConstC, denote, *, right_distrib, denote_mulMonC, add_assoc, zsmul_eq_intCast_mul]
|
||||
<;> simp [denote_combineC, denote_mulConstC, denote, *, right_distrib, denote_mulMonC, add_assoc]
|
||||
|
||||
theorem Poly.denote_mulC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) (p₁ p₂ : Poly)
|
||||
: (mulC p₁ p₂ c).denote ctx = p₁.denote ctx * p₂.denote ctx := by
|
||||
@@ -1004,7 +949,6 @@ theorem Expr.denote_toPolyC {α c} [CommRing α] [IsCharP α c] (ctx : Context
|
||||
next => rw [IsCharP.intCast_emod]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul]
|
||||
next => rw [intCast_neg, neg_mul, intCast_one, one_mul, sub_eq_add_neg]
|
||||
next a k h => simp at h; simp [h, Semiring.pow_zero, Ring.intCast_one]
|
||||
next => rw [IsCharP.intCast_emod, intCast_pow]
|
||||
next => simp [Poly.denote_ofMon, Mon.denote, Power.denote_eq, mul_one]
|
||||
|
||||
@@ -1046,7 +990,7 @@ theorem NullCert.eq_nzdivC {α c} [CommRing α] [IsCharP α c] [NoNatZeroDivisor
|
||||
apply eqsImplies_helper
|
||||
intro h₃
|
||||
replace h₂ := congrArg (Poly.denote ctx) h₂
|
||||
simp [Expr.denote_toPolyC, Poly.denote_mulConstC, denote_toPolyC, h₃, Expr.denote, ← zsmul_eq_intCast_mul] at h₂
|
||||
simp [Expr.denote_toPolyC, Poly.denote_mulConstC, denote_toPolyC, h₃, Expr.denote] at h₂
|
||||
replace h₂ := no_int_zero_divisors h₁ h₂
|
||||
rw [sub_eq_zero_iff] at h₂
|
||||
assumption
|
||||
@@ -1122,7 +1066,7 @@ def div_cert (p₁ : Poly) (k : Int) (p : Poly) : Bool :=
|
||||
def div {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: div_cert p₁ k p → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [div_cert]; intro hnz _ h; subst p₁
|
||||
simp [Poly.denote_mulConst, ← zsmul_eq_intCast_mul] at h
|
||||
simp [Poly.denote_mulConst] at h
|
||||
exact no_int_zero_divisors hnz h
|
||||
|
||||
@[expose]
|
||||
@@ -1175,7 +1119,7 @@ def imp_keq_cert (lhs rhs : Expr) (k : Int) (p₁ p₂ : Poly) : Bool :=
|
||||
theorem imp_keq {α} [CommRing α] (ctx : Context α) [NoNatZeroDivisors α] (k : Int) (lhs rhs : Expr) (p₁ p₂ : Poly)
|
||||
: imp_keq_cert lhs rhs k p₁ p₂ → k * p₁.denote ctx = p₂.denote ctx → lhs.denote ctx = rhs.denote ctx := by
|
||||
simp [imp_keq_cert]; intro hnz _ _; subst p₁ p₂
|
||||
simp [Expr.denote_toPoly, Expr.denote, Poly.denote, intCast_zero, ← zsmul_eq_intCast_mul]
|
||||
simp [Expr.denote_toPoly, Expr.denote, Poly.denote, intCast_zero]
|
||||
intro h; replace h := no_int_zero_divisors hnz h
|
||||
rw [← sub_eq_zero_iff, h]
|
||||
|
||||
@@ -1216,7 +1160,7 @@ def div_certC (p₁ : Poly) (k : Int) (p : Poly) (c : Nat) : Bool :=
|
||||
def divC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) [NoNatZeroDivisors α] (p₁ : Poly) (k : Int) (p : Poly)
|
||||
: div_certC p₁ k p c → p₁.denote ctx = 0 → p.denote ctx = 0 := by
|
||||
simp [div_certC]; intro hnz _ h; subst p₁
|
||||
simp [Poly.denote_mulConstC, ← zsmul_eq_intCast_mul] at h
|
||||
simp [Poly.denote_mulConstC] at h
|
||||
exact no_int_zero_divisors hnz h
|
||||
|
||||
@[expose]
|
||||
@@ -1275,7 +1219,7 @@ def imp_keq_certC (lhs rhs : Expr) (k : Int) (p₁ p₂ : Poly) (c : Nat) : Bool
|
||||
theorem imp_keqC {α c} [CommRing α] [IsCharP α c] (ctx : Context α) [NoNatZeroDivisors α] (k : Int) (lhs rhs : Expr) (p₁ p₂ : Poly)
|
||||
: imp_keq_certC lhs rhs k p₁ p₂ c → k * p₁.denote ctx = p₂.denote ctx → lhs.denote ctx = rhs.denote ctx := by
|
||||
simp [imp_keq_certC]; intro hnz _ _; subst p₁ p₂
|
||||
simp [Expr.denote_toPolyC, Expr.denote, Poly.denote, intCast_zero, ← zsmul_eq_intCast_mul]
|
||||
simp [Expr.denote_toPolyC, Expr.denote, Poly.denote, intCast_zero]
|
||||
intro h; replace h := no_int_zero_divisors hnz h
|
||||
rw [← sub_eq_zero_iff, h]
|
||||
|
||||
@@ -1297,8 +1241,8 @@ where
|
||||
@[expose]
|
||||
def Poly.denoteAsIntModule [CommRing α] (ctx : Context α) (p : Poly) : α :=
|
||||
match p with
|
||||
| .num k => HMul.hMul (α := Int) k (One.one : α)
|
||||
| .add k m p => HMul.hMul (α := Int) k (m.denoteAsIntModule ctx) + denoteAsIntModule ctx p
|
||||
| .num k => Int.cast k * One.one
|
||||
| .add k m p => Int.cast k * m.denoteAsIntModule ctx + denoteAsIntModule ctx p
|
||||
|
||||
theorem Mon.denoteAsIntModule_go_eq_denote {α} [CommRing α] (ctx : Context α) (m : Mon) (acc : α)
|
||||
: denoteAsIntModule.go ctx m acc = acc * m.denote ctx := by
|
||||
@@ -1309,7 +1253,7 @@ theorem Mon.denoteAsIntModule_eq_denote {α} [CommRing α] (ctx : Context α) (m
|
||||
cases m <;> simp [denoteAsIntModule, denote, denoteAsIntModule_go_eq_denote]; rfl
|
||||
|
||||
theorem Poly.denoteAsIntModule_eq_denote {α} [CommRing α] (ctx : Context α) (p : Poly) : p.denoteAsIntModule ctx = p.denote ctx := by
|
||||
induction p <;> simp [*, denoteAsIntModule, denote, mul_one, One.one, Mon.denoteAsIntModule_eq_denote, Ring.zsmul_eq_intCast_mul]
|
||||
induction p <;> simp [*, denoteAsIntModule, denote, mul_one, One.one, Mon.denoteAsIntModule_eq_denote]
|
||||
|
||||
open Stepwise
|
||||
|
||||
@@ -1407,7 +1351,7 @@ theorem one_eq_zero_unsat {α} [Field α] (ctx : Context α) (p : Poly) : one_eq
|
||||
theorem diseq_to_eq {α} [Field α] (a b : α) : a ≠ b → (a - b)*(a - b)⁻¹ = 1 := by
|
||||
intro h
|
||||
have : a - b ≠ 0 := by
|
||||
intro h'; rw [sub_eq_zero_iff.mp h'] at h
|
||||
intro h'; rw [Ring.sub_eq_zero_iff.mp h'] at h
|
||||
contradiction
|
||||
exact Field.mul_inv_cancel this
|
||||
|
||||
@@ -1432,10 +1376,9 @@ theorem Poly.normEq0_eq {α} [CommRing α] (ctx : Context α) (p : Poly) (c : Na
|
||||
simp [denote, normEq0]; split <;> simp [denote]
|
||||
next h' => rw [of_mod_eq_0 h h', Ring.intCast_zero]
|
||||
next a m p ih =>
|
||||
simp [denote, normEq0]; split <;> simp [denote, zsmul_eq_intCast_mul, *]
|
||||
next h' => rw [of_mod_eq_0 h h', Semiring.zero_mul, zero_add]
|
||||
simp [denote, normEq0]; split <;> simp [denote, *]
|
||||
next h' => rw [of_mod_eq_0 h h', Semiring.zero_mul, Semiring.zero_add]
|
||||
|
||||
@[expose]
|
||||
def eq_normEq0_cert (c : Nat) (p₁ p₂ p : Poly) : Bool :=
|
||||
p₁ == .num c && p == p₂.normEq0 c
|
||||
|
||||
@@ -1452,10 +1395,9 @@ theorem gcd_eq_0 [CommRing α] (g n m a b : Int) (h : g = a * n + b * m)
|
||||
replace h₂ := congrArg (Int.cast (R := α) b * ·) h₂; simp at h₂
|
||||
rw [← Ring.intCast_mul, Ring.intCast_zero, Semiring.mul_zero] at h₂
|
||||
replace h₁ := congrArg (· + Int.cast (b * m)) h₁; simp at h₁
|
||||
rw [← Ring.intCast_add, h₂, zero_add, ← h] at h₁
|
||||
rw [← Ring.intCast_add, h₂, Semiring.zero_add, ← h] at h₁
|
||||
rw [Ring.intCast_zero, h₁]
|
||||
|
||||
@[expose]
|
||||
def eq_gcd_cert (a b : Int) (p₁ p₂ p : Poly) : Bool :=
|
||||
match p₁ with
|
||||
| .add .. => false
|
||||
@@ -1473,7 +1415,6 @@ theorem eq_gcd {α} [CommRing α] (ctx : Context α) (a b : Int) (p₁ p₂ p :
|
||||
next n m g =>
|
||||
apply gcd_eq_0 g n m a b
|
||||
|
||||
@[expose]
|
||||
def d_normEq0_cert (c : Nat) (p₁ p₂ p : Poly) : Bool :=
|
||||
p₂ == .num c && p == p₁.normEq0 c
|
||||
|
||||
@@ -1482,11 +1423,5 @@ theorem d_normEq0 {α} [CommRing α] (ctx : Context α) (k : Int) (c : Nat) (ini
|
||||
simp [d_normEq0_cert]; intro _ h₁ h₂; subst p p₂; simp [Poly.denote]
|
||||
intro h; rw [p₁.normEq0_eq] <;> assumption
|
||||
|
||||
@[expose] def norm_int_cert (e : Expr) (p : Poly) : Bool :=
|
||||
e.toPoly == p
|
||||
|
||||
theorem norm_int (ctx : Context Int) (e : Expr) (p : Poly) : norm_int_cert e p → e.denote ctx = p.denote' ctx := by
|
||||
simp [norm_int_cert, Poly.denote'_eq_denote]; intro; subst p; simp [Expr.denote_toPoly]
|
||||
|
||||
end CommRing
|
||||
end Lean.Grind
|
||||
|
||||
@@ -72,11 +72,11 @@ syntax grindGen := ppSpace &"gen"
|
||||
syntax grindEq := "=" (grindGen)?
|
||||
syntax grindEqBoth := atomic("_" "=" "_") (grindGen)?
|
||||
syntax grindEqRhs := atomic("=" "_") (grindGen)?
|
||||
syntax grindEqBwd := patternIgnore(atomic("←" "=") <|> atomic("<-" "="))
|
||||
syntax grindBwd := patternIgnore("←" <|> "<-") (grindGen)?
|
||||
syntax grindFwd := patternIgnore("→" <|> "->")
|
||||
syntax grindRL := patternIgnore("⇐" <|> "<=")
|
||||
syntax grindLR := patternIgnore("⇒" <|> "=>")
|
||||
syntax grindEqBwd := atomic("←" "=") <|> atomic("<-" "=")
|
||||
syntax grindBwd := ("←" <|> "<-") (grindGen)?
|
||||
syntax grindFwd := "→" <|> "->"
|
||||
syntax grindRL := "⇐" <|> "<="
|
||||
syntax grindLR := "⇒" <|> "=>"
|
||||
syntax grindUsr := &"usr"
|
||||
syntax grindCases := &"cases"
|
||||
syntax grindCasesEager := atomic(&"cases" &"eager")
|
||||
@@ -86,8 +86,8 @@ syntax grindMod :=
|
||||
grindEqBoth <|> grindEqRhs <|> grindEq <|> grindEqBwd <|> grindBwd
|
||||
<|> grindFwd <|> grindRL <|> grindLR <|> grindUsr <|> grindCasesEager
|
||||
<|> grindCases <|> grindIntro <|> grindExt <|> grindGen
|
||||
syntax (name := grind) "grind" (ppSpace grindMod)? : attr
|
||||
syntax (name := grind?) "grind?" (ppSpace grindMod)? : attr
|
||||
syntax (name := grind) "grind" ppSpace (grindMod)? : attr
|
||||
syntax (name := grind?) "grind?" ppSpace (grindMod)? : attr
|
||||
end Attr
|
||||
end Lean.Parser
|
||||
|
||||
@@ -206,17 +206,17 @@ namespace Lean.Parser.Tactic
|
||||
-/
|
||||
|
||||
syntax grindErase := "-" ident
|
||||
syntax grindLemma := ppGroup((Attr.grindMod ppSpace)? ident)
|
||||
syntax grindLemma := (Attr.grindMod ppSpace)? ident
|
||||
syntax grindParam := grindErase <|> grindLemma
|
||||
|
||||
/--
|
||||
`grind` is a tactic inspired by modern SMT solvers. **Picture a virtual whiteboard**:
|
||||
every time grind discovers a new equality, inequality, or logical fact,
|
||||
it writes it on the board, groups together terms known to be equal,
|
||||
and lets each reasoning engine read from and contribute to the shared workspace.
|
||||
These engines work together to handle equality reasoning, apply known theorems,
|
||||
propagate new facts, perform case analysis, and run specialized solvers
|
||||
for domains like linear arithmetic and commutative rings.
|
||||
`grind` is a tactic inspired by modern SMT solvers.
|
||||
**Picture a virtual white‑board:** every time `grind` discovers a new equality, inequality,
|
||||
or Boolean literal it writes that fact on the board, merges equivalent terms into buckets,
|
||||
and invites each engine to read from, and add back to, the same workspace.
|
||||
The cooperating engines are: congruence closure, constraint propagation, E‑matching,
|
||||
guided case analysis, and a suite of satellite theory solvers (linear integer arithmetic,
|
||||
commutative rings, ...).
|
||||
|
||||
`grind` is *not* designed for goals whose search space explodes combinatorially,
|
||||
think large pigeonhole instances, graph‑coloring reductions, high‑order N‑queens boards,
|
||||
@@ -227,28 +227,15 @@ For **bit‑level or combinatorial problems**, consider using **`bv_decide`**.
|
||||
`bv_decide` calls a state‑of‑the‑art SAT solver (CaDiCaL) and then returns a
|
||||
*compact, machine‑checkable certificate*.
|
||||
|
||||
### Equality reasoning
|
||||
|
||||
`grind` uses **congruence closure** to track equalities between terms.
|
||||
When two terms are known to be equal, congruence closure automatically deduces
|
||||
equalities between more complex expressions built from them.
|
||||
For example, if `a = b`, then congruence closure will also conclude that `f a` = `f b`
|
||||
for any function `f`. This forms the foundation for efficient equality reasoning in `grind`.
|
||||
Here is an example:
|
||||
```
|
||||
example (f : Nat → Nat) (h : a = b) : f (f b) = f (f a) := by
|
||||
grind
|
||||
```
|
||||
|
||||
### Applying theorems using E-matching
|
||||
|
||||
To apply existing theorems, `grind` uses a technique called **E-matching**,
|
||||
which finds matches for known theorem patterns while taking equalities into account.
|
||||
Combined with congruence closure, E-matching helps `grind` discover
|
||||
non-obvious consequences of theorems and equalities automatically.
|
||||
E-matching is a mechanism used by `grind` to instantiate theorems efficiently.
|
||||
It is especially effective when combined with congruence closure, enabling
|
||||
`grind` to discover non-obvious consequences of equalities and annotated theorems
|
||||
automatically. The theorem instantiation process is interrupted using the `generation` threshold.
|
||||
Terms occurring in the input goal have `generation` zero. When `grind` instantiates
|
||||
a theorem using terms with generation `≤ n`, the new generated terms have generation `n+1`.
|
||||
|
||||
Consider the following functions and theorems:
|
||||
```
|
||||
```lean
|
||||
def f (a : Nat) : Nat :=
|
||||
a + 1
|
||||
|
||||
@@ -261,9 +248,9 @@ theorem gf (x : Nat) : g (f x) = x := by
|
||||
```
|
||||
The theorem `gf` asserts that `g (f x) = x` for all natural numbers `x`.
|
||||
The attribute `[grind =]` instructs `grind` to use the left-hand side of the equation,
|
||||
`g (f x)`, as a pattern for E-matching.
|
||||
`g (f x)`, as a pattern for heuristic instantiation via E-matching.
|
||||
Suppose we now have a goal involving:
|
||||
```
|
||||
```lean
|
||||
example {a b} (h : f b = a) : g a = b := by
|
||||
grind
|
||||
```
|
||||
@@ -281,7 +268,7 @@ For example, the pattern `g (f x)` is too restrictive in the following case:
|
||||
the theorem `gf` will not be instantiated because the goal does not even
|
||||
contain the function symbol `g`.
|
||||
|
||||
```
|
||||
```lean (error := true)
|
||||
example (h₁ : f b = a) (h₂ : f c = a) : b = c := by
|
||||
grind
|
||||
```
|
||||
@@ -289,7 +276,7 @@ example (h₁ : f b = a) (h₂ : f c = a) : b = c := by
|
||||
You can use the command `grind_pattern` to manually select a pattern for a given theorem.
|
||||
In the following example, we instruct `grind` to use `f x` as the pattern,
|
||||
allowing it to solve the goal automatically:
|
||||
```
|
||||
```lean
|
||||
grind_pattern gf => f x
|
||||
|
||||
example {a b c} (h₁ : f b = a) (h₂ : f c = a) : b = c := by
|
||||
@@ -298,25 +285,6 @@ example {a b c} (h₁ : f b = a) (h₂ : f c = a) : b = c := by
|
||||
You can enable the option `trace.grind.ematch.instance` to make `grind` print a
|
||||
trace message for each theorem instance it generates.
|
||||
|
||||
You can also specify a **multi-pattern** to control when `grind` should apply a theorem.
|
||||
A multi-pattern requires that all specified patterns are matched in the current context
|
||||
before the theorem is applied. This is useful for theorems such as transitivity rules,
|
||||
where multiple premises must be simultaneously present for the rule to apply.
|
||||
The following example demonstrates this feature using a transitivity axiom for a binary relation `R`:
|
||||
```
|
||||
opaque R : Int → Int → Prop
|
||||
axiom Rtrans {x y z : Int} : R x y → R y z → R x z
|
||||
|
||||
grind_pattern Rtrans => R x y, R y z
|
||||
|
||||
example {a b c d} : R a b → R b c → R c d → R a d := by
|
||||
grind
|
||||
```
|
||||
By specifying the multi-pattern `R x y, R y z`, we instruct `grind` to
|
||||
instantiate `Rtrans` only when both `R x y` and `R y z` are available in the context.
|
||||
In the example, `grind` applies `Rtrans` to derive `R a c` from `R a b` and `R b c`,
|
||||
and can then repeat the same reasoning to deduce `R a d` from `R a c` and `R c d`.
|
||||
|
||||
Instead of using `grind_pattern` to explicitly specify a pattern,
|
||||
you can use the `@[grind]` attribute or one of its variants, which will use a heuristic to
|
||||
generate a (multi-)pattern. The complete list is available in the reference manual. The main ones are:
|
||||
@@ -332,61 +300,45 @@ generate a (multi-)pattern. The complete list is available in the reference manu
|
||||
- `@[grind =]` checks that the conclusion of the theorem is an equality, and then uses the left-hand-side of the equality as a pattern.
|
||||
This may fail if not all of the arguments appear in the left-hand-side.
|
||||
|
||||
Here is the previous example again but using the attribute `[grind →]`
|
||||
```
|
||||
opaque R : Int → Int → Prop
|
||||
@[grind →] axiom Rtrans {x y z : Int} : R x y → R y z → R x z
|
||||
Main configuration options:
|
||||
|
||||
example {a b c d} : R a b → R b c → R c d → R a d := by
|
||||
grind
|
||||
```
|
||||
|
||||
To control theorem instantiation and avoid generating an unbounded number of instances,
|
||||
`grind` uses a generation counter. Terms in the original goal are assigned generation zero.
|
||||
When `grind` applies a theorem using terms of generation `≤ n`, any new terms it creates
|
||||
are assigned generation `n + 1`. This limits how far the tactic explores when applying
|
||||
theorems and helps prevent an excessive number of instantiations.
|
||||
|
||||
#### Key options:
|
||||
- `grind (splits := <num>)` caps the *depth* of the search tree. Once a branch performs `num` splits
|
||||
`grind` stops splitting further in that branch.
|
||||
- `grind -splitIte` disables case splitting on if-then-else expressions.
|
||||
- `grind -splitMatch` disables case splitting on `match` expressions.
|
||||
- `grind +splitImp` instructs `grind` to split on any hypothesis `A → B` whose antecedent `A` is **propositional**.
|
||||
- `grind (ematch := <num>)` controls the number of E-matching rounds.
|
||||
- `grind [<name>, ...]` instructs `grind` to use the declaration `name` during E-matching.
|
||||
- `grind only [<name>, ...]` is like `grind [<name>, ...]` but does not use theorems tagged with `@[grind]`.
|
||||
- `grind (gen := <num>)` sets the maximum generation.
|
||||
- `grind -ring` disables the ring solver based on Gröbner basis.
|
||||
- `grind (ringSteps := <num>)` limits the number of steps performed by ring solver.
|
||||
- `grind -cutsat` disables the linear integer arithmetic solver based on the cutsat procedure.
|
||||
- `grind -linarith` disables the linear arithmetic solver for (ordered) modules and rings.
|
||||
|
||||
### Linear integer arithmetic (`cutsat`)
|
||||
|
||||
`grind` can solve goals that reduce to **linear integer arithmetic (LIA)** using an
|
||||
integrated decision procedure called **`cutsat`**. It understands
|
||||
|
||||
* equalities `p = 0`
|
||||
* inequalities `p ≤ 0`
|
||||
* disequalities `p ≠ 0`
|
||||
* divisibility `d ∣ p`
|
||||
|
||||
The solver incrementally assigns integer values to variables; when a partial
|
||||
assignment violates a constraint it adds a new, implied constraint and retries.
|
||||
This *model-based* search is **complete for LIA**.
|
||||
|
||||
#### Key options:
|
||||
|
||||
* `grind -cutsat` disable the solver (useful for debugging)
|
||||
* `grind +qlia` accept rational models (shrinks the search space but is incomplete for ℤ)
|
||||
|
||||
#### Examples:
|
||||
|
||||
Examples:
|
||||
```
|
||||
-- Even + even is never odd.
|
||||
example {x y : Int} : 2 * x + 4 * y ≠ 5 := by
|
||||
example {a b} {as bs : List α} : (as ++ bs ++ [b]).getLastD a = b := by
|
||||
grind
|
||||
|
||||
-- Mixing equalities and inequalities.
|
||||
example {x y : Int} :
|
||||
2 * x + 3 * y = 0 → 1 ≤ x → y < 1 := by
|
||||
example (x : BitVec (w+1)) : (BitVec.cons x.msb (x.setWidth w)) = x := by
|
||||
grind
|
||||
|
||||
-- Reasoning with divisibility.
|
||||
example (a b : Int) :
|
||||
2 ∣ a + 1 → 2 ∣ b + a → ¬ 2 ∣ b + 2 * a := by
|
||||
example (a b c : UInt64) : a ≤ 2 → b ≤ 3 → c - a - b = 0 → c ≤ 5 := by
|
||||
grind
|
||||
|
||||
example [Field α] (a : α) : (2 : α) ≠ 0 → 1 / a + 1 / (2 * a) = 3 / (2 * a) := by
|
||||
grind
|
||||
|
||||
example (as : Array α) (lo hi i j : Nat) :
|
||||
lo ≤ i → i < j → j ≤ hi → j < as.size → min lo (as.size - 1) ≤ i := by
|
||||
grind
|
||||
|
||||
example [CommRing α] [NoNatZeroDivisors α] (a b c : α)
|
||||
: a + b + c = 3 →
|
||||
a^2 + b^2 + c^2 = 5 →
|
||||
a^3 + b^3 + c^3 = 7 →
|
||||
a^4 + b^4 = 9 - c^4 := by
|
||||
grind
|
||||
|
||||
example (x y : Int) :
|
||||
@@ -395,91 +347,12 @@ example (x y : Int) :
|
||||
-10 ≤ 7*x - 9*y →
|
||||
7*x - 9*y ≤ 4 → False := by
|
||||
grind
|
||||
|
||||
-- Types that implement the `ToInt` type-class.
|
||||
example (a b c : UInt64)
|
||||
: a ≤ 2 → b ≤ 3 → c - a - b = 0 → c ≤ 5 := by
|
||||
grind
|
||||
```
|
||||
|
||||
### Algebraic solver (`ring`)
|
||||
|
||||
`grind` ships with an algebraic solver nick-named **`ring`** for goals that can
|
||||
be phrased as polynomial equations (or disequations) over commutative rings,
|
||||
semirings, or fields.
|
||||
|
||||
*Works out of the box*
|
||||
All core numeric types and relevant Mathlib types already provide the required
|
||||
type-class instances, so the solver is ready to use in most developments.
|
||||
|
||||
What it can decide:
|
||||
|
||||
* equalities of the form `p = q`
|
||||
* disequalities `p ≠ q`
|
||||
* basic reasoning under field inverses (`a / b := a * b⁻¹`)
|
||||
* goals that mix ring facts with other `grind` engines
|
||||
|
||||
#### Key options:
|
||||
|
||||
* `grind -ring` turn the solver off (useful when debugging)
|
||||
* `grind (ringSteps := n)` cap the number of steps performed by this procedure.
|
||||
|
||||
#### Examples
|
||||
|
||||
```
|
||||
open Lean Grind
|
||||
|
||||
example [CommRing α] (x : α) : (x + 1) * (x - 1) = x^2 - 1 := by
|
||||
grind
|
||||
|
||||
-- Characteristic 256 means 16 * 16 = 0.
|
||||
example [CommRing α] [IsCharP α 256] (x : α) :
|
||||
(x + 16) * (x - 16) = x^2 := by
|
||||
grind
|
||||
|
||||
-- Works on built-in rings such as `UInt8`.
|
||||
example (x : UInt8) : (x + 16) * (x - 16) = x^2 := by
|
||||
grind
|
||||
|
||||
example [CommRing α] (a b c : α) :
|
||||
a + b + c = 3 →
|
||||
a^2 + b^2 + c^2 = 5 →
|
||||
a^3 + b^3 + c^3 = 7 →
|
||||
a^4 + b^4 = 9 - c^4 := by
|
||||
grind
|
||||
|
||||
example [Field α] [NoNatZeroDivisors α] (a : α) :
|
||||
1 / a + 1 / (2 * a) = 3 / (2 * a) := by
|
||||
grind
|
||||
```
|
||||
|
||||
### Other options
|
||||
|
||||
- `grind (splits := <num>)` caps the *depth* of the search tree. Once a branch performs `num` splits
|
||||
`grind` stops splitting further in that branch.
|
||||
- `grind -splitIte` disables case splitting on if-then-else expressions.
|
||||
- `grind -splitMatch` disables case splitting on `match` expressions.
|
||||
- `grind +splitImp` instructs `grind` to split on any hypothesis `A → B` whose antecedent `A` is **propositional**.
|
||||
- `grind -linarith` disables the linear arithmetic solver for (ordered) modules and rings.
|
||||
|
||||
### Additional Examples
|
||||
|
||||
```
|
||||
example {a b} {as bs : List α} : (as ++ bs ++ [b]).getLastD a = b := by
|
||||
grind
|
||||
|
||||
example (x : BitVec (w+1)) : (BitVec.cons x.msb (x.setWidth w)) = x := by
|
||||
grind
|
||||
|
||||
example (as : Array α) (lo hi i j : Nat) :
|
||||
lo ≤ i → i < j → j ≤ hi → j < as.size → min lo (as.size - 1) ≤ i := by
|
||||
grind
|
||||
```
|
||||
-/
|
||||
syntax (name := grind)
|
||||
"grind" optConfig (&" only")?
|
||||
(" [" withoutPosition(grindParam,*) "]")?
|
||||
(&" on_failure " term)? : tactic
|
||||
("on_failure " term)? : tactic
|
||||
|
||||
/--
|
||||
`grind?` takes the same arguments as `grind`, but reports an equivalent call to `grind only`
|
||||
@@ -489,6 +362,6 @@ theorems in a local invocation.
|
||||
syntax (name := grindTrace)
|
||||
"grind?" optConfig (&" only")?
|
||||
(" [" withoutPosition(grindParam,*) "]")?
|
||||
(&" on_failure " term)? : tactic
|
||||
("on_failure " term)? : tactic
|
||||
|
||||
end Lean.Parser.Tactic
|
||||
|
||||
@@ -16,8 +16,6 @@ public section
|
||||
namespace Lean.Grind
|
||||
|
||||
instance : CommRing (BitVec w) where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := BitVec.add_assoc
|
||||
add_comm := BitVec.add_comm
|
||||
add_zero := BitVec.add_zero
|
||||
@@ -35,12 +33,6 @@ instance : CommRing (BitVec w) where
|
||||
pow_succ _ _ := BitVec.pow_succ
|
||||
ofNat_succ x := BitVec.ofNat_add x 1
|
||||
intCast_neg _ := BitVec.ofInt_neg
|
||||
neg_zsmul i x := by
|
||||
change (BitVec.ofInt _ (-i) * x = _)
|
||||
rw [BitVec.ofInt_neg]
|
||||
rw [BitVec.neg_mul]
|
||||
rfl
|
||||
zsmul_natCast_eq_nsmul _ _ := rfl
|
||||
|
||||
instance : IsCharP (BitVec w) (2 ^ w) := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by simp [BitVec.toNat_eq])
|
||||
|
||||
@@ -74,29 +74,6 @@ private theorem neg_neg [NeZero n] (a : Fin n) : - - a = a := by
|
||||
have : NeZero (n - (a + 1)) := ⟨by omega⟩
|
||||
rw [Nat.self_sub_mod, Nat.sub_sub_eq_min, Nat.min_eq_right (Nat.le_of_lt h)]
|
||||
|
||||
theorem _root_.Nat.sub_sub_right (a : Nat) {b c : Nat} (h : c ≤ b) : a - (b - c) = a + c - b := by omega
|
||||
|
||||
theorem neg_mul [NeZero n] (a b : Fin n) : (-a) * b = -(a * b) := by
|
||||
rcases a with ⟨a, ha⟩; rcases b with ⟨b, hb⟩
|
||||
ext
|
||||
simp only [Fin.neg_def, Fin.mul_def, Nat.mod_mul_mod]
|
||||
rw [Nat.sub_mul]
|
||||
rw [Nat.mod_eq_mod_iff]
|
||||
match b with
|
||||
| 0 => refine ⟨1, 0, by simp⟩
|
||||
| b+1 =>
|
||||
refine ⟨a*(b+1)/n, b, ?_⟩
|
||||
rw [Nat.mod_def, Nat.mul_add_one, Nat.mul_comm _ n, Nat.mul_comm b n]
|
||||
have : n * (a * (b + 1) / n) ≤ a * (b + 1) := Nat.mul_div_le (a * (b + 1)) n
|
||||
have := Nat.lt_mul_div_succ (a * (b + 1)) (show 0 < n by omega)
|
||||
rw [Nat.mul_add_one n] at this
|
||||
have : a * (b + 1) ≤ n * b + n := by
|
||||
rw [Nat.mul_add_one]
|
||||
have := Nat.mul_le_mul_right b ha
|
||||
rw [Nat.succ_mul] at this
|
||||
omega
|
||||
omega
|
||||
|
||||
open Fin.NatCast Fin.IntCast in
|
||||
theorem intCast_neg [NeZero n] (i : Int) : Int.cast (R := Fin n) (-i) = - Int.cast (R := Fin n) i := by
|
||||
simp [Int.cast, IntCast.intCast, Fin.intCast]
|
||||
@@ -104,10 +81,7 @@ theorem intCast_neg [NeZero n] (i : Int) : Int.cast (R := Fin n) (-i) = - Int.ca
|
||||
next h₁ h₂ => simp [Int.le_antisymm h₁ h₂, Fin.neg_def]
|
||||
next => simp [Fin.neg_neg]
|
||||
|
||||
open Fin.NatCast Fin.IntCast in
|
||||
instance (n : Nat) [NeZero n] : CommRing (Fin n) where
|
||||
nsmul := ⟨fun k i => (k : Fin n) * i⟩
|
||||
zsmul := ⟨fun k i => (k : Fin n) * i⟩
|
||||
natCast := Fin.NatCast.instNatCast n
|
||||
intCast := Fin.IntCast.instIntCast n
|
||||
add_assoc := Fin.add_assoc
|
||||
@@ -124,8 +98,6 @@ instance (n : Nat) [NeZero n] : CommRing (Fin n) where
|
||||
ofNat_succ := Fin.ofNat_succ
|
||||
sub_eq_add_neg := Fin.sub_eq_add_neg
|
||||
intCast_neg := Fin.intCast_neg
|
||||
neg_zsmul i a := by simp [intCast_neg, neg_mul]
|
||||
zsmul_natCast_eq_nsmul _ _ := rfl
|
||||
|
||||
instance (n : Nat) [NeZero n] : IsCharP (Fin n) n := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
|
||||
@@ -14,7 +14,6 @@ public section
|
||||
namespace Lean.Grind
|
||||
|
||||
instance : CommRing Int where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
add_assoc := Int.add_assoc
|
||||
add_comm := Int.add_comm
|
||||
add_zero := Int.add_zero
|
||||
@@ -31,7 +30,6 @@ instance : CommRing Int where
|
||||
pow_succ _ _ := by rfl
|
||||
ofNat_succ _ := by rfl
|
||||
sub_eq_add_neg _ _ := Int.sub_eq_add_neg
|
||||
neg_zsmul := Int.neg_mul
|
||||
|
||||
instance : IsCharP Int 0 := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by erw [Int.ofNat_eq_zero]; simp)
|
||||
|
||||
@@ -17,25 +17,13 @@ public section
|
||||
|
||||
namespace Lean.Grind
|
||||
|
||||
@[expose]
|
||||
def Int8.natCast : NatCast Int8 where
|
||||
instance : NatCast Int8 where
|
||||
natCast x := Int8.ofNat x
|
||||
|
||||
@[expose]
|
||||
def Int8.intCast : IntCast Int8 where
|
||||
instance : IntCast Int8 where
|
||||
intCast x := Int8.ofInt x
|
||||
|
||||
attribute [local instance] Int8.intCast in
|
||||
theorem Int8.intCast_neg (i : Int) : ((-i : Int) : Int8) = -(i : Int8) :=
|
||||
Int8.ofInt_neg _
|
||||
|
||||
attribute [local instance] Int8.intCast in
|
||||
theorem Int8.intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : Int8) = OfNat.ofNat x := Int8.ofInt_eq_ofNat
|
||||
|
||||
attribute [local instance] Int8.natCast Int8.intCast in
|
||||
instance : CommRing Int8 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := Int8.add_assoc
|
||||
add_comm := Int8.add_comm
|
||||
add_zero := Int8.add_zero
|
||||
@@ -53,8 +41,6 @@ instance : CommRing Int8 where
|
||||
pow_succ := Int8.pow_succ
|
||||
ofNat_succ x := Int8.ofNat_add x 1
|
||||
intCast_neg := Int8.ofInt_neg
|
||||
neg_zsmul i x := by simp [Int8.intCast_neg, Int8.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (Int8.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP Int8 (2 ^ 8) := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -70,25 +56,13 @@ example : ToInt.Sub Int8 (.sint 8) := inferInstance
|
||||
|
||||
instance : ToInt.Pow Int8 (.sint 8) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
@[expose]
|
||||
def Int16.natCast : NatCast Int16 where
|
||||
instance : NatCast Int16 where
|
||||
natCast x := Int16.ofNat x
|
||||
|
||||
@[expose]
|
||||
def Int16.intCast : IntCast Int16 where
|
||||
instance : IntCast Int16 where
|
||||
intCast x := Int16.ofInt x
|
||||
|
||||
attribute [local instance] Int16.intCast in
|
||||
theorem Int16.intCast_neg (i : Int) : ((-i : Int) : Int16) = -(i : Int16) :=
|
||||
Int16.ofInt_neg _
|
||||
|
||||
attribute [local instance] Int16.intCast in
|
||||
theorem Int16.intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : Int16) = OfNat.ofNat x := Int16.ofInt_eq_ofNat
|
||||
|
||||
attribute [local instance] Int16.natCast Int16.intCast in
|
||||
instance : CommRing Int16 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := Int16.add_assoc
|
||||
add_comm := Int16.add_comm
|
||||
add_zero := Int16.add_zero
|
||||
@@ -106,8 +80,6 @@ instance : CommRing Int16 where
|
||||
pow_succ := Int16.pow_succ
|
||||
ofNat_succ x := Int16.ofNat_add x 1
|
||||
intCast_neg := Int16.ofInt_neg
|
||||
neg_zsmul i x := by simp [Int16.intCast_neg, Int16.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (Int16.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP Int16 (2 ^ 16) := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -123,25 +95,13 @@ example : ToInt.Sub Int16 (.sint 16) := inferInstance
|
||||
|
||||
instance : ToInt.Pow Int16 (.sint 16) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
@[expose]
|
||||
def Int32.natCast : NatCast Int32 where
|
||||
instance : NatCast Int32 where
|
||||
natCast x := Int32.ofNat x
|
||||
|
||||
@[expose]
|
||||
def Int32.intCast : IntCast Int32 where
|
||||
instance : IntCast Int32 where
|
||||
intCast x := Int32.ofInt x
|
||||
|
||||
attribute [local instance] Int32.intCast in
|
||||
theorem Int32.intCast_neg (i : Int) : ((-i : Int) : Int32) = -(i : Int32) :=
|
||||
Int32.ofInt_neg _
|
||||
|
||||
attribute [local instance] Int32.intCast in
|
||||
theorem Int32.intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : Int32) = OfNat.ofNat x := Int32.ofInt_eq_ofNat
|
||||
|
||||
attribute [local instance] Int32.natCast Int32.intCast in
|
||||
instance : CommRing Int32 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := Int32.add_assoc
|
||||
add_comm := Int32.add_comm
|
||||
add_zero := Int32.add_zero
|
||||
@@ -159,8 +119,6 @@ instance : CommRing Int32 where
|
||||
pow_succ := Int32.pow_succ
|
||||
ofNat_succ x := Int32.ofNat_add x 1
|
||||
intCast_neg := Int32.ofInt_neg
|
||||
neg_zsmul i x := by simp [Int32.intCast_neg, Int32.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (Int32.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP Int32 (2 ^ 32) := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -176,25 +134,13 @@ example : ToInt.Sub Int32 (.sint 32) := inferInstance
|
||||
|
||||
instance : ToInt.Pow Int32 (.sint 32) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
@[expose]
|
||||
def Int64.natCast : NatCast Int64 where
|
||||
instance : NatCast Int64 where
|
||||
natCast x := Int64.ofNat x
|
||||
|
||||
@[expose]
|
||||
def Int64.intCast : IntCast Int64 where
|
||||
instance : IntCast Int64 where
|
||||
intCast x := Int64.ofInt x
|
||||
|
||||
attribute [local instance] Int64.intCast in
|
||||
theorem Int64.intCast_neg (i : Int) : ((-i : Int) : Int64) = -(i : Int64) :=
|
||||
Int64.ofInt_neg _
|
||||
|
||||
attribute [local instance] Int64.intCast in
|
||||
theorem Int64.intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : Int64) = OfNat.ofNat x := Int64.ofInt_eq_ofNat
|
||||
|
||||
attribute [local instance] Int64.natCast Int64.intCast in
|
||||
instance : CommRing Int64 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := Int64.add_assoc
|
||||
add_comm := Int64.add_comm
|
||||
add_zero := Int64.add_zero
|
||||
@@ -212,8 +158,6 @@ instance : CommRing Int64 where
|
||||
pow_succ := Int64.pow_succ
|
||||
ofNat_succ x := Int64.ofNat_add x 1
|
||||
intCast_neg := Int64.ofInt_neg
|
||||
neg_zsmul i x := by simp [Int64.intCast_neg, Int64.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (Int64.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP Int64 (2 ^ 64) := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -229,25 +173,13 @@ example : ToInt.Sub Int64 (.sint 64) := inferInstance
|
||||
|
||||
instance : ToInt.Pow Int64 (.sint 64) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
@[expose]
|
||||
def ISize.natCast : NatCast ISize where
|
||||
instance : NatCast ISize where
|
||||
natCast x := ISize.ofNat x
|
||||
|
||||
@[expose]
|
||||
def ISize.intCast : IntCast ISize where
|
||||
instance : IntCast ISize where
|
||||
intCast x := ISize.ofInt x
|
||||
|
||||
attribute [local instance] ISize.intCast in
|
||||
theorem ISize.intCast_neg (i : Int) : ((-i : Int) : ISize) = -(i : ISize) :=
|
||||
ISize.ofInt_neg _
|
||||
|
||||
attribute [local instance] ISize.intCast in
|
||||
theorem ISize.intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : ISize) = OfNat.ofNat x := ISize.ofInt_eq_ofNat
|
||||
|
||||
attribute [local instance] ISize.natCast ISize.intCast in
|
||||
instance : CommRing ISize where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := ISize.add_assoc
|
||||
add_comm := ISize.add_comm
|
||||
add_zero := ISize.add_zero
|
||||
@@ -265,9 +197,6 @@ instance : CommRing ISize where
|
||||
pow_succ := ISize.pow_succ
|
||||
ofNat_succ x := ISize.ofNat_add x 1
|
||||
intCast_neg := ISize.ofInt_neg
|
||||
neg_zsmul i x := by simp [ISize.intCast_neg, ISize.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (ISize.intCast_ofNat _)
|
||||
|
||||
open System.Platform (numBits)
|
||||
|
||||
instance : IsCharP ISize (2 ^ numBits) := IsCharP.mk' _ _
|
||||
|
||||
@@ -18,19 +18,12 @@ namespace UInt8
|
||||
/-- Variant of `UInt8.ofNat_mod_size` replacing `2 ^ 8` with `256`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 256) = ofNat x := ofNat_mod_size
|
||||
|
||||
@[expose]
|
||||
def natCast : NatCast UInt8 where
|
||||
instance : NatCast UInt8 where
|
||||
natCast x := UInt8.ofNat x
|
||||
|
||||
@[expose]
|
||||
def intCast : IntCast UInt8 where
|
||||
instance : IntCast UInt8 where
|
||||
intCast x := UInt8.ofInt x
|
||||
|
||||
attribute [local instance] natCast intCast
|
||||
|
||||
theorem intCast_neg (x : Int) : ((-x : Int) : UInt8) = - (x : UInt8) := by
|
||||
simp only [Int.cast, IntCast.intCast, UInt8.ofInt_neg]
|
||||
|
||||
theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt8) = OfNat.ofNat x := by
|
||||
-- A better proof would be welcome!
|
||||
simp only [Int.cast, IntCast.intCast]
|
||||
@@ -48,19 +41,12 @@ namespace UInt16
|
||||
/-- Variant of `UInt16.ofNat_mod_size` replacing `2 ^ 16` with `65536`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 65536) = ofNat x := ofNat_mod_size
|
||||
|
||||
@[expose]
|
||||
def natCast : NatCast UInt16 where
|
||||
instance : NatCast UInt16 where
|
||||
natCast x := UInt16.ofNat x
|
||||
|
||||
@[expose]
|
||||
def intCast : IntCast UInt16 where
|
||||
instance : IntCast UInt16 where
|
||||
intCast x := UInt16.ofInt x
|
||||
|
||||
attribute [local instance] natCast intCast
|
||||
|
||||
theorem intCast_neg (x : Int) : ((-x : Int) : UInt16) = - (x : UInt16) := by
|
||||
simp only [Int.cast, IntCast.intCast, UInt16.ofInt_neg]
|
||||
|
||||
theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt16) = OfNat.ofNat x := by
|
||||
-- A better proof would be welcome!
|
||||
simp only [Int.cast, IntCast.intCast]
|
||||
@@ -78,19 +64,12 @@ namespace UInt32
|
||||
/-- Variant of `UInt32.ofNat_mod_size` replacing `2 ^ 32` with `4294967296`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 4294967296) = ofNat x := ofNat_mod_size
|
||||
|
||||
@[expose]
|
||||
def natCast : NatCast UInt32 where
|
||||
instance : NatCast UInt32 where
|
||||
natCast x := UInt32.ofNat x
|
||||
|
||||
@[expose]
|
||||
def intCast : IntCast UInt32 where
|
||||
instance : IntCast UInt32 where
|
||||
intCast x := UInt32.ofInt x
|
||||
|
||||
attribute [local instance] natCast intCast
|
||||
|
||||
theorem intCast_neg (x : Int) : ((-x : Int) : UInt32) = - (x : UInt32) := by
|
||||
simp only [Int.cast, IntCast.intCast, UInt32.ofInt_neg]
|
||||
|
||||
theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt32) = OfNat.ofNat x := by
|
||||
-- A better proof would be welcome!
|
||||
simp only [Int.cast, IntCast.intCast]
|
||||
@@ -108,19 +87,12 @@ namespace UInt64
|
||||
/-- Variant of `UInt64.ofNat_mod_size` replacing `2 ^ 64` with `18446744073709551616`.-/
|
||||
theorem ofNat_mod_size' : ofNat (x % 18446744073709551616) = ofNat x := ofNat_mod_size
|
||||
|
||||
@[expose]
|
||||
def natCast : NatCast UInt64 where
|
||||
instance : NatCast UInt64 where
|
||||
natCast x := UInt64.ofNat x
|
||||
|
||||
@[expose]
|
||||
def intCast : IntCast UInt64 where
|
||||
instance : IntCast UInt64 where
|
||||
intCast x := UInt64.ofInt x
|
||||
|
||||
attribute [local instance] natCast intCast
|
||||
|
||||
theorem intCast_neg (x : Int) : ((-x : Int) : UInt64) = - (x : UInt64) := by
|
||||
simp only [Int.cast, IntCast.intCast, UInt64.ofInt_neg]
|
||||
|
||||
theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : UInt64) = OfNat.ofNat x := by
|
||||
-- A better proof would be welcome!
|
||||
simp only [Int.cast, IntCast.intCast]
|
||||
@@ -135,19 +107,12 @@ end UInt64
|
||||
|
||||
namespace USize
|
||||
|
||||
@[expose]
|
||||
def natCast : NatCast USize where
|
||||
instance : NatCast USize where
|
||||
natCast x := USize.ofNat x
|
||||
|
||||
@[expose]
|
||||
def intCast : IntCast USize where
|
||||
instance : IntCast USize where
|
||||
intCast x := USize.ofInt x
|
||||
|
||||
attribute [local instance] natCast intCast
|
||||
|
||||
theorem intCast_neg (x : Int) : ((-x : Int) : USize) = - (x : USize) := by
|
||||
simp only [Int.cast, IntCast.intCast, USize.ofInt_neg]
|
||||
|
||||
theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : USize) = OfNat.ofNat x := by
|
||||
-- A better proof would be welcome!
|
||||
simp only [Int.cast, IntCast.intCast]
|
||||
@@ -162,10 +127,7 @@ theorem intCast_ofNat (x : Nat) : (OfNat.ofNat (α := Int) x : USize) = OfNat.of
|
||||
end USize
|
||||
namespace Lean.Grind
|
||||
|
||||
attribute [local instance] UInt8.natCast UInt8.intCast in
|
||||
instance : CommRing UInt8 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := UInt8.add_assoc
|
||||
add_comm := UInt8.add_comm
|
||||
add_zero := UInt8.add_zero
|
||||
@@ -184,8 +146,6 @@ instance : CommRing UInt8 where
|
||||
ofNat_succ x := UInt8.ofNat_add x 1
|
||||
intCast_neg := UInt8.ofInt_neg
|
||||
intCast_ofNat := UInt8.intCast_ofNat
|
||||
neg_zsmul i a := by simp [UInt8.intCast_neg, UInt8.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (UInt8.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP UInt8 256 := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -199,10 +159,7 @@ example : ToInt.Sub UInt8 (.uint 8) := inferInstance
|
||||
|
||||
instance : ToInt.Pow UInt8 (.uint 8) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
attribute [local instance] UInt16.natCast UInt16.intCast in
|
||||
instance : CommRing UInt16 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := UInt16.add_assoc
|
||||
add_comm := UInt16.add_comm
|
||||
add_zero := UInt16.add_zero
|
||||
@@ -221,8 +178,6 @@ instance : CommRing UInt16 where
|
||||
ofNat_succ x := UInt16.ofNat_add x 1
|
||||
intCast_neg := UInt16.ofInt_neg
|
||||
intCast_ofNat := UInt16.intCast_ofNat
|
||||
neg_zsmul i a := by simp [UInt16.intCast_neg, UInt16.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (UInt16.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP UInt16 65536 := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -236,10 +191,7 @@ example : ToInt.Sub UInt16 (.uint 16) := inferInstance
|
||||
|
||||
instance : ToInt.Pow UInt16 (.uint 16) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
attribute [local instance] UInt32.natCast UInt32.intCast in
|
||||
instance : CommRing UInt32 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := UInt32.add_assoc
|
||||
add_comm := UInt32.add_comm
|
||||
add_zero := UInt32.add_zero
|
||||
@@ -258,8 +210,6 @@ instance : CommRing UInt32 where
|
||||
ofNat_succ x := UInt32.ofNat_add x 1
|
||||
intCast_neg := UInt32.ofInt_neg
|
||||
intCast_ofNat := UInt32.intCast_ofNat
|
||||
neg_zsmul i a := by simp [UInt32.intCast_neg, UInt32.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (UInt32.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP UInt32 4294967296 := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -273,10 +223,7 @@ example : ToInt.Sub UInt32 (.uint 32) := inferInstance
|
||||
|
||||
instance : ToInt.Pow UInt32 (.uint 32) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
attribute [local instance] UInt64.natCast UInt64.intCast in
|
||||
instance : CommRing UInt64 where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := UInt64.add_assoc
|
||||
add_comm := UInt64.add_comm
|
||||
add_zero := UInt64.add_zero
|
||||
@@ -295,8 +242,6 @@ instance : CommRing UInt64 where
|
||||
ofNat_succ x := UInt64.ofNat_add x 1
|
||||
intCast_neg := UInt64.ofInt_neg
|
||||
intCast_ofNat := UInt64.intCast_ofNat
|
||||
neg_zsmul i a := by simp [UInt64.intCast_neg, UInt64.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (UInt64.intCast_ofNat _)
|
||||
|
||||
instance : IsCharP UInt64 18446744073709551616 := IsCharP.mk' _ _
|
||||
(ofNat_eq_zero_iff := fun x => by
|
||||
@@ -310,10 +255,7 @@ example : ToInt.Sub UInt64 (.uint 64) := inferInstance
|
||||
|
||||
instance : ToInt.Pow UInt64 (.uint 64) := ToInt.pow_of_semiring (by simp)
|
||||
|
||||
attribute [local instance] USize.natCast USize.intCast in
|
||||
instance : CommRing USize where
|
||||
nsmul := ⟨(· * ·)⟩
|
||||
zsmul := ⟨(· * ·)⟩
|
||||
add_assoc := USize.add_assoc
|
||||
add_comm := USize.add_comm
|
||||
add_zero := USize.add_zero
|
||||
@@ -332,8 +274,6 @@ instance : CommRing USize where
|
||||
ofNat_succ x := USize.ofNat_add x 1
|
||||
intCast_neg := USize.ofInt_neg
|
||||
intCast_ofNat := USize.intCast_ofNat
|
||||
neg_zsmul i a := by simp [USize.intCast_neg, USize.neg_mul]
|
||||
zsmul_natCast_eq_nsmul n a := congrArg (· * a) (USize.intCast_ofNat _)
|
||||
|
||||
open System.Platform
|
||||
|
||||
|
||||
@@ -544,6 +544,12 @@ end fun_order
|
||||
|
||||
section monotone_lemmas
|
||||
|
||||
theorem monotone_letFun
|
||||
{α : Sort u} {β : Sort v} {γ : Sort w} [PartialOrder α] [PartialOrder β]
|
||||
(v : γ) (k : α → γ → β)
|
||||
(hmono : ∀ y, monotone (fun x => k x y)) :
|
||||
monotone fun (x : α) => letFun v (k x) := hmono v
|
||||
|
||||
@[partial_fixpoint_monotone]
|
||||
theorem monotone_ite
|
||||
{α : Sort u} {β : Sort v} [PartialOrder α] [PartialOrder β]
|
||||
|
||||
@@ -63,14 +63,20 @@ Examples:
|
||||
fun _ => a
|
||||
|
||||
/--
|
||||
`letFun v (fun x => b)` is a function version of `have x := v; b`.
|
||||
The encoding of `let_fun x := v; b` is `letFun v (fun x => b)`.
|
||||
This is equal to `(fun x => b) v`, so the value of `x` is not accessible to `b`.
|
||||
This is in contrast to `let x := v; b`, where the value of `x` is accessible to `b`.
|
||||
|
||||
This used to be the way `have`/`let_fun` syntax was encoded,
|
||||
and there used to be special support for `letFun` in WHNF and `simp`.
|
||||
There is special support for `letFun`.
|
||||
Both WHNF and `simp` are aware of `letFun` and can reduce it when zeta reduction is enabled,
|
||||
despite the fact it is marked `irreducible`.
|
||||
For metaprogramming, the function `Lean.Expr.letFun?` can be used to recognize a `let_fun` expression
|
||||
to extract its parts as if it were a `let` expression.
|
||||
-/
|
||||
def letFun {α : Sort u} {β : α → Sort v} (v : α) (f : (x : α) → β x) : β v := f v
|
||||
-- We need to export the body of `letFun`, which is suppressed if `[irreducible]` is set directly.
|
||||
-- We can work around this rare case by applying the attribute after the fact.
|
||||
attribute [irreducible] letFun
|
||||
|
||||
set_option checkBinderAnnotations false in
|
||||
/--
|
||||
|
||||
@@ -137,6 +137,21 @@ theorem have_body_congr' {α : Sort u} {β : Sort v} (a : α) {f f' : α → β}
|
||||
(h : ∀ x, f x = f' x) : f a = f' a :=
|
||||
h a
|
||||
|
||||
theorem letFun_unused {α : Sort u} {β : Sort v} (a : α) {b b' : β} (h : b = b') : @letFun α (fun _ => β) a (fun _ => b) = b' :=
|
||||
h
|
||||
|
||||
theorem letFun_congr {α : Sort u} {β : Sort v} {a a' : α} {f f' : α → β} (h₁ : a = a') (h₂ : ∀ x, f x = f' x)
|
||||
: @letFun α (fun _ => β) a f = @letFun α (fun _ => β) a' f' := by
|
||||
rw [h₁, funext h₂]
|
||||
|
||||
theorem letFun_body_congr {α : Sort u} {β : Sort v} (a : α) {f f' : α → β} (h : ∀ x, f x = f' x)
|
||||
: @letFun α (fun _ => β) a f = @letFun α (fun _ => β) a f' := by
|
||||
rw [funext h]
|
||||
|
||||
theorem letFun_val_congr {α : Sort u} {β : Sort v} {a a' : α} {f : α → β} (h : a = a')
|
||||
: @letFun α (fun _ => β) a f = @letFun α (fun _ => β) a' f := by
|
||||
rw [h]
|
||||
|
||||
@[congr]
|
||||
theorem ite_congr {x y u v : α} {s : Decidable b} [Decidable c]
|
||||
(h₁ : b = c) (h₂ : c → x = u) (h₃ : ¬ c → y = v) : ite b x y = ite c u v := by
|
||||
|
||||
@@ -544,7 +544,7 @@ performs the unification, and replaces the target with the unified version of `t
|
||||
syntax (name := «show») "show " term : tactic
|
||||
|
||||
/--
|
||||
Extracts `let` and `have` expressions from within the target or a local hypothesis,
|
||||
Extracts `let` and `let_fun` expressions from within the target or a local hypothesis,
|
||||
introducing new local definitions.
|
||||
|
||||
- `extract_lets` extracts all the lets from the target.
|
||||
@@ -558,7 +558,7 @@ introduces a new local definition `z := v` and changes `h` to be `h : b z`.
|
||||
syntax (name := extractLets) "extract_lets " optConfig (ppSpace colGt (ident <|> hole))* (location)? : tactic
|
||||
|
||||
/--
|
||||
Lifts `let` and `have` expressions within a term as far out as possible.
|
||||
Lifts `let` and `let_fun` expressions within a term as far out as possible.
|
||||
It is like `extract_lets +lift`, but the top-level lets at the end of the procedure
|
||||
are not extracted as local hypotheses.
|
||||
|
||||
@@ -663,7 +663,7 @@ A simp lemma specification is:
|
||||
* optional `←` to use the lemma backward
|
||||
* `thm` for the theorem to rewrite with
|
||||
-/
|
||||
syntax simpLemma := ppGroup((simpPre <|> simpPost)? patternIgnore("← " <|> "<- ")? term)
|
||||
syntax simpLemma := (simpPre <|> simpPost)? patternIgnore("← " <|> "<- ")? term
|
||||
/-- An erasure specification `-thm` says to remove `thm` from the simp set -/
|
||||
syntax simpErase := "-" term:max
|
||||
/-- The simp lemma specification `*` means to rewrite with all hypotheses -/
|
||||
@@ -1281,10 +1281,10 @@ syntax (name := substEqs) "subst_eqs" : tactic
|
||||
/-- The `run_tac doSeq` tactic executes code in `TacticM Unit`. -/
|
||||
syntax (name := runTac) "run_tac " doSeq : tactic
|
||||
|
||||
/-- `haveI` behaves like `have`, but inlines the value instead of producing a `have` term. -/
|
||||
/-- `haveI` behaves like `have`, but inlines the value instead of producing a `let_fun` term. -/
|
||||
macro "haveI" c:letConfig d:letDecl : tactic => `(tactic| refine_lift haveI $c:letConfig $d:letDecl; ?_)
|
||||
|
||||
/-- `letI` behaves like `let`, but inlines the value instead of producing a `let` term. -/
|
||||
/-- `letI` behaves like `let`, but inlines the value instead of producing a `let_fun` term. -/
|
||||
macro "letI" c:letConfig d:letDecl : tactic => `(tactic| refine_lift letI $c:letConfig $d:letDecl; ?_)
|
||||
|
||||
/--
|
||||
|
||||
@@ -44,7 +44,8 @@ noncomputable abbrev Acc.ndrecOn.{u1, u2} {α : Sort u2} {r : α → α → Prop
|
||||
namespace Acc
|
||||
variable {α : Sort u} {r : α → α → Prop}
|
||||
|
||||
theorem inv {x y : α} (h₁ : Acc r x) (h₂ : r y x) : Acc r y :=
|
||||
-- `def` for `WellFounded.fix`
|
||||
def inv {x y : α} (h₁ : Acc r x) (h₂ : r y x) : Acc r y :=
|
||||
h₁.recOn (fun _ ac₁ _ h₂ => ac₁ y h₂) h₂
|
||||
|
||||
end Acc
|
||||
@@ -77,8 +78,8 @@ class WellFoundedRelation (α : Sort u) where
|
||||
wf : WellFounded rel
|
||||
|
||||
namespace WellFounded
|
||||
|
||||
theorem apply {α : Sort u} {r : α → α → Prop} (wf : WellFounded r) (a : α) : Acc r a :=
|
||||
-- `def` for `WellFounded.fix`
|
||||
def apply {α : Sort u} {r : α → α → Prop} (wf : WellFounded r) (a : α) : Acc r a :=
|
||||
wf.rec (fun p => p) a
|
||||
|
||||
section
|
||||
@@ -158,13 +159,15 @@ end Subrelation
|
||||
namespace InvImage
|
||||
variable {α : Sort u} {β : Sort v} {r : β → β → Prop}
|
||||
|
||||
theorem accAux (f : α → β) {b : β} (ac : Acc r b) : (x : α) → f x = b → Acc (InvImage r f) x :=
|
||||
def accAux (f : α → β) {b : β} (ac : Acc r b) : (x : α) → f x = b → Acc (InvImage r f) x :=
|
||||
Acc.recOn ac fun _ _ ih => fun _ e => Acc.intro _ (fun y lt => ih (f y) (e ▸ lt) y rfl)
|
||||
|
||||
theorem accessible {a : α} (f : α → β) (ac : Acc r (f a)) : Acc (InvImage r f) a :=
|
||||
-- `def` for `WellFounded.fix`
|
||||
def accessible {a : α} (f : α → β) (ac : Acc r (f a)) : Acc (InvImage r f) a :=
|
||||
accAux f ac a rfl
|
||||
|
||||
theorem wf (f : α → β) (h : WellFounded r) : WellFounded (InvImage r f) :=
|
||||
-- `def` for `WellFounded.fix`
|
||||
def wf (f : α → β) (h : WellFounded r) : WellFounded (InvImage r f) :=
|
||||
⟨fun a => accessible f (apply h (f a))⟩
|
||||
end InvImage
|
||||
|
||||
|
||||
@@ -64,12 +64,11 @@ Checks whether the declaration was originally declared as a theorem; see also
|
||||
def wasOriginallyTheorem (env : Environment) (declName : Name) : Bool :=
|
||||
getOriginalConstKind? env declName |>.map (· matches .thm) |>.getD false
|
||||
|
||||
/-- If `warn.sorry` is set to true, then, so long as the message log does not already have any errors,
|
||||
declarations with `sorryAx` generate the "declaration uses 'sorry'" warning. -/
|
||||
register_builtin_option warn.sorry : Bool := {
|
||||
defValue := true
|
||||
descr := "warn about uses of `sorry` in declarations added to the environment"
|
||||
}
|
||||
private def looksLikeRelevantTheoremProofType (type : Expr) : Bool :=
|
||||
if let .forallE _ _ type _ := type then
|
||||
looksLikeRelevantTheoremProofType type
|
||||
else
|
||||
type.isAppOfArity ``WellFounded 2
|
||||
|
||||
def addDecl (decl : Declaration) : CoreM Unit := do
|
||||
-- register namespaces for newly added constants; this used to be done by the kernel itself
|
||||
@@ -83,7 +82,10 @@ def addDecl (decl : Declaration) : CoreM Unit := do
|
||||
let mut exportedInfo? := none
|
||||
let (name, info, kind) ← match decl with
|
||||
| .thmDecl thm =>
|
||||
if (← getEnv).header.isModule then
|
||||
let exportProof := !(← getEnv).header.isModule ||
|
||||
-- TODO: this is horrible...
|
||||
looksLikeRelevantTheoremProofType thm.type
|
||||
if !exportProof then
|
||||
exportedInfo? := some <| .axiomInfo { thm with isUnsafe := false }
|
||||
pure (thm.name, .thmInfo thm, .thm)
|
||||
| .defnDecl defn | .mutualDefnDecl [defn] =>
|
||||
@@ -133,9 +135,8 @@ where
|
||||
doAdd := do
|
||||
profileitM Exception "type checking" (← getOptions) do
|
||||
withTraceNode `Kernel (fun _ => return m!"typechecking declarations {decl.getTopLevelNames}") do
|
||||
if warn.sorry.get (← getOptions) then
|
||||
if !(← MonadLog.hasErrors) && decl.hasSorry then
|
||||
logWarning <| .tagged `hasSorry m!"declaration uses 'sorry'"
|
||||
if !(← MonadLog.hasErrors) && decl.hasSorry then
|
||||
logWarning <| .tagged `hasSorry m!"declaration uses 'sorry'"
|
||||
try
|
||||
let env ← (← getEnv).addDeclAux (← getOptions) decl (← read).cancelTk?
|
||||
|> ofExceptKernelException
|
||||
|
||||
@@ -20,9 +20,9 @@ import Lean.Compiler.IR.ExpandResetReuse
|
||||
import Lean.Compiler.IR.UnboxResult
|
||||
import Lean.Compiler.IR.ElimDeadBranches
|
||||
import Lean.Compiler.IR.EmitC
|
||||
import Lean.Compiler.IR.CtorLayout
|
||||
import Lean.Compiler.IR.Sorry
|
||||
import Lean.Compiler.IR.ToIR
|
||||
import Lean.Compiler.IR.ToIRType
|
||||
|
||||
-- The following imports are not required by the compiler. They are here to ensure that there
|
||||
-- are no orphaned modules.
|
||||
|
||||
@@ -114,10 +114,8 @@ def checkPartialApp (c : FunId) (ys : Array Arg) : M Unit := do
|
||||
checkArgs ys
|
||||
|
||||
def checkExpr (ty : IRType) : Expr → M Unit
|
||||
-- Partial applications should always produce a closure object.
|
||||
| Expr.pap f ys => checkPartialApp f ys *> checkObjType ty
|
||||
-- Applications of closures should always produce a boxed value.
|
||||
| Expr.ap x ys => checkObjVar x *> checkArgs ys *> checkObjType ty
|
||||
| Expr.pap f ys => checkPartialApp f ys *> checkObjType ty -- partial applications should always produce a closure object
|
||||
| Expr.ap x ys => checkObjVar x *> checkArgs ys
|
||||
| Expr.fap f ys => checkFullApp f ys
|
||||
| Expr.ctor c ys => do
|
||||
if c.cidx > maxCtorTag && (c.size > 0 || c.usize > 0 || c.ssize > 0) then
|
||||
|
||||
43
src/Lean/Compiler/IR/CtorLayout.lean
Normal file
43
src/Lean/Compiler/IR/CtorLayout.lean
Normal file
@@ -0,0 +1,43 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.Environment
|
||||
import Lean.Compiler.IR.Format
|
||||
|
||||
namespace Lean
|
||||
namespace IR
|
||||
|
||||
inductive CtorFieldInfo where
|
||||
| irrelevant
|
||||
| object (i : Nat)
|
||||
| usize (i : Nat)
|
||||
| scalar (sz : Nat) (offset : Nat) (type : IRType)
|
||||
deriving Inhabited
|
||||
|
||||
namespace CtorFieldInfo
|
||||
|
||||
def format : CtorFieldInfo → Format
|
||||
| irrelevant => "◾"
|
||||
| object i => f!"obj@{i}"
|
||||
| usize i => f!"usize@{i}"
|
||||
| scalar sz offset type => f!"scalar#{sz}@{offset}:{type}"
|
||||
|
||||
instance : ToFormat CtorFieldInfo := ⟨format⟩
|
||||
|
||||
end CtorFieldInfo
|
||||
|
||||
structure CtorLayout where
|
||||
cidx : Nat
|
||||
fieldInfo : List CtorFieldInfo
|
||||
numObjs : Nat
|
||||
numUSize : Nat
|
||||
scalarSize : Nat
|
||||
|
||||
@[extern "lean_ir_get_ctor_layout"]
|
||||
opaque getCtorLayout (env : @& Environment) (ctorName : @& Name) : Except String CtorLayout
|
||||
|
||||
end IR
|
||||
end Lean
|
||||
@@ -9,14 +9,14 @@ import Lean.Compiler.LCNF.CompilerM
|
||||
import Lean.Compiler.LCNF.PhaseExt
|
||||
import Lean.Compiler.IR.Basic
|
||||
import Lean.Compiler.IR.CompilerM
|
||||
import Lean.Compiler.IR.ToIRType
|
||||
import Lean.Compiler.IR.CtorLayout
|
||||
import Lean.CoreM
|
||||
import Lean.Environment
|
||||
|
||||
namespace Lean.IR
|
||||
|
||||
open Lean.Compiler (LCNF.Alt LCNF.Arg LCNF.Code LCNF.Decl LCNF.DeclValue LCNF.LCtx LCNF.LetDecl
|
||||
LCNF.LetValue LCNF.LitValue LCNF.Param LCNF.getMonoDecl?)
|
||||
open Lean.Compiler (LCNF.Alt LCNF.Arg LCNF.CacheExtension LCNF.Code LCNF.Decl LCNF.DeclValue
|
||||
LCNF.LCtx LCNF.LetDecl LCNF.LetValue LCNF.LitValue LCNF.Param LCNF.getMonoDecl?)
|
||||
|
||||
namespace ToIR
|
||||
|
||||
@@ -72,6 +72,86 @@ def lowerLitValue (v : LCNF.LitValue) : LitVal :=
|
||||
| .uint32 v => .num (UInt32.toNat v)
|
||||
| .uint64 v | .usize v => .num (UInt64.toNat v)
|
||||
|
||||
builtin_initialize scalarTypeExt : LCNF.CacheExtension Name (Option IRType) ←
|
||||
LCNF.CacheExtension.register
|
||||
|
||||
def lowerEnumToScalarType? (name : Name) : CoreM (Option IRType) := do
|
||||
match (← scalarTypeExt.find? name) with
|
||||
| some info? => return info?
|
||||
| none =>
|
||||
let info? ← fillCache
|
||||
scalarTypeExt.insert name info?
|
||||
return info?
|
||||
where fillCache : CoreM (Option IRType) := do
|
||||
let env ← Lean.getEnv
|
||||
let some (.inductInfo inductiveVal) := env.find? name | return none
|
||||
let ctorNames := inductiveVal.ctors
|
||||
let numCtors := ctorNames.length
|
||||
for ctorName in ctorNames do
|
||||
let some (.ctorInfo ctorVal) := env.find? ctorName | panic! "expected valid constructor name"
|
||||
if ctorVal.type.isForall then return none
|
||||
return if numCtors == 1 then
|
||||
none
|
||||
else if numCtors < Nat.pow 2 8 then
|
||||
some .uint8
|
||||
else if numCtors < Nat.pow 2 16 then
|
||||
some .uint16
|
||||
else if numCtors < Nat.pow 2 32 then
|
||||
some .uint32
|
||||
else
|
||||
none
|
||||
|
||||
def lowerType (e : Lean.Expr) : CoreM IRType := do
|
||||
match e with
|
||||
| .const name .. =>
|
||||
match name with
|
||||
| ``UInt8 | ``Bool => return .uint8
|
||||
| ``UInt16 => return .uint16
|
||||
| ``UInt32 => return .uint32
|
||||
| ``UInt64 => return .uint64
|
||||
| ``USize => return .usize
|
||||
| ``Float => return .float
|
||||
| ``Float32 => return .float32
|
||||
| ``lcErased => return .irrelevant
|
||||
| _ =>
|
||||
if let some scalarType ← lowerEnumToScalarType? name then
|
||||
return scalarType
|
||||
else
|
||||
return .object
|
||||
| .app f _ =>
|
||||
-- All mono types are in headBeta form.
|
||||
if let .const name _ := f then
|
||||
if let some scalarType ← lowerEnumToScalarType? name then
|
||||
return scalarType
|
||||
else
|
||||
return .object
|
||||
else
|
||||
return .object
|
||||
| .forallE .. => return .object
|
||||
| _ => panic! "invalid type"
|
||||
|
||||
builtin_initialize ctorInfoExt : LCNF.CacheExtension Name (CtorInfo × (Array CtorFieldInfo)) ←
|
||||
LCNF.CacheExtension.register
|
||||
|
||||
def getCtorInfo (name : Name) : CoreM (CtorInfo × (Array CtorFieldInfo)) := do
|
||||
match (← ctorInfoExt.find? name) with
|
||||
| some info => return info
|
||||
| none =>
|
||||
let info ← fillCache
|
||||
ctorInfoExt.insert name info
|
||||
return info
|
||||
where fillCache := do
|
||||
match getCtorLayout (← Lean.getEnv) name with
|
||||
| .ok ctorLayout =>
|
||||
return ⟨{
|
||||
name,
|
||||
cidx := ctorLayout.cidx,
|
||||
size := ctorLayout.numObjs,
|
||||
usize := ctorLayout.numUSize,
|
||||
ssize := ctorLayout.scalarSize
|
||||
}, ctorLayout.fieldInfo.toArray⟩
|
||||
| .error .. => panic! "unrecognized constructor"
|
||||
|
||||
def lowerArg (a : LCNF.Arg) : M Arg := do
|
||||
match a with
|
||||
| .fvar fvarId =>
|
||||
@@ -96,7 +176,7 @@ def lowerProj (base : VarId) (ctorInfo : CtorInfo) (field : CtorFieldInfo)
|
||||
|
||||
def lowerParam (p : LCNF.Param) : M Param := do
|
||||
let x ← bindVar p.fvarId
|
||||
let ty ← toIRType p.type
|
||||
let ty ← lowerType p.type
|
||||
return { x, borrow := p.borrow, ty }
|
||||
|
||||
mutual
|
||||
@@ -118,7 +198,7 @@ partial def lowerCode (c : LCNF.Code) : M FnBody := do
|
||||
| some (.var varId) =>
|
||||
return .case cases.typeName
|
||||
varId
|
||||
(← toIRType cases.resultType)
|
||||
(← lowerType cases.resultType)
|
||||
(← cases.alts.mapM (lowerAlt varId))
|
||||
| some (.joinPoint ..) | some .erased | none => panic! "unexpected value"
|
||||
| .return fvarId =>
|
||||
@@ -138,8 +218,8 @@ partial def lowerLet (decl : LCNF.LetDecl) (k : LCNF.Code) : M FnBody := do
|
||||
let rec mkExpr (e : Expr) : M FnBody := do
|
||||
let var ← bindVar decl.fvarId
|
||||
let type ← match e with
|
||||
| .ctor .. | .pap .. | .ap .. | .proj .. => pure <| .object
|
||||
| _ => toIRType decl.type
|
||||
| .ctor .. | .pap .. | .proj .. => pure <| .object
|
||||
| _ => lowerType decl.type
|
||||
return .vdecl var type e (← lowerCode k)
|
||||
let rec mkErased (_ : Unit) : M FnBody := do
|
||||
bindErased decl.fvarId
|
||||
@@ -147,7 +227,10 @@ partial def lowerLet (decl : LCNF.LetDecl) (k : LCNF.Code) : M FnBody := do
|
||||
let rec mkPartialApp (e : Expr) (restArgs : Array Arg) : M FnBody := do
|
||||
let var ← bindVar decl.fvarId
|
||||
let tmpVar ← newVar
|
||||
return .vdecl tmpVar .object e (.vdecl var .object (.ap tmpVar restArgs) (← lowerCode k))
|
||||
let type ← match e with
|
||||
| .ctor .. | .pap .. | .proj .. => pure <| .object
|
||||
| _ => lowerType decl.type
|
||||
return .vdecl tmpVar .object e (.vdecl var type (.ap tmpVar restArgs) (← lowerCode k))
|
||||
let rec tryIrDecl? (name : Name) (args : Array Arg) : M (Option FnBody) := do
|
||||
if let some decl ← LCNF.getMonoDecl? name then
|
||||
let numArgs := args.size
|
||||
@@ -173,7 +256,7 @@ partial def lowerLet (decl : LCNF.LetDecl) (k : LCNF.Code) : M FnBody := do
|
||||
let some (.inductInfo { ctors, .. }) := (← Lean.getEnv).find? typeName
|
||||
| panic! "projection of non-inductive type"
|
||||
let ctorName := ctors[0]!
|
||||
let ⟨ctorInfo, fields⟩ ← getCtorLayout ctorName
|
||||
let ⟨ctorInfo, fields⟩ ← getCtorInfo ctorName
|
||||
let ⟨result, type⟩ := lowerProj varId ctorInfo fields[i]!
|
||||
match result with
|
||||
| .expr e =>
|
||||
@@ -205,47 +288,45 @@ partial def lowerLet (decl : LCNF.LetDecl) (k : LCNF.Code) : M FnBody := do
|
||||
return code
|
||||
else
|
||||
mkExpr (.fap name irArgs)
|
||||
else if let some scalarType ← lowerEnumToScalarType? ctorVal.name then
|
||||
assert! args.isEmpty
|
||||
let var ← bindVar decl.fvarId
|
||||
return .vdecl var scalarType (.lit (.num ctorVal.cidx)) (← lowerCode k)
|
||||
else
|
||||
let type ← nameToIRType ctorVal.induct
|
||||
if type.isScalar then
|
||||
let var ← bindVar decl.fvarId
|
||||
return .vdecl var type (.lit (.num ctorVal.cidx)) (← lowerCode k)
|
||||
else
|
||||
assert! type == .object
|
||||
let ⟨ctorInfo, fields⟩ ← getCtorLayout name
|
||||
let args := args.extract (start := ctorVal.numParams)
|
||||
let objArgs : Array Arg ← do
|
||||
let mut result : Array Arg := #[]
|
||||
for i in [0:fields.size] do
|
||||
match args[i]! with
|
||||
| .fvar fvarId =>
|
||||
if let some (.var varId) := (← get).fvars[fvarId]? then
|
||||
if fields[i]! matches .object .. then
|
||||
result := result.push (.var varId)
|
||||
| .type _ | .erased =>
|
||||
let ⟨ctorInfo, fields⟩ ← getCtorInfo name
|
||||
let args := args.extract (start := ctorVal.numParams)
|
||||
let objArgs : Array Arg ← do
|
||||
let mut result : Array Arg := #[]
|
||||
for i in [0:fields.size] do
|
||||
match args[i]! with
|
||||
| .fvar fvarId =>
|
||||
if let some (.var varId) := (← get).fvars[fvarId]? then
|
||||
if fields[i]! matches .object .. then
|
||||
result := result.push .irrelevant
|
||||
pure result
|
||||
let objVar ← bindVar decl.fvarId
|
||||
let rec lowerNonObjectFields (_ : Unit) : M FnBody :=
|
||||
let rec loop (usizeCount : Nat) (i : Nat) : M FnBody := do
|
||||
match args[i]? with
|
||||
| some (.fvar fvarId) =>
|
||||
match (← get).fvars[fvarId]? with
|
||||
| some (.var varId) =>
|
||||
match fields[i]! with
|
||||
| .usize .. =>
|
||||
let k ← loop (usizeCount + 1) (i + 1)
|
||||
return .uset objVar (ctorInfo.size + usizeCount) varId k
|
||||
| .scalar _ offset argType =>
|
||||
let k ← loop usizeCount (i + 1)
|
||||
return .sset objVar (ctorInfo.size + ctorInfo.usize) offset varId argType k
|
||||
| .object .. | .irrelevant => loop usizeCount (i + 1)
|
||||
| _ => loop usizeCount (i + 1)
|
||||
| some (.type _) | some .erased => loop usizeCount (i + 1)
|
||||
| none => lowerCode k
|
||||
loop 0 0
|
||||
return .vdecl objVar type (.ctor ctorInfo objArgs) (← lowerNonObjectFields ())
|
||||
result := result.push (.var varId)
|
||||
| .type _ | .erased =>
|
||||
if fields[i]! matches .object .. then
|
||||
result := result.push .irrelevant
|
||||
pure result
|
||||
let objVar ← bindVar decl.fvarId
|
||||
let rec lowerNonObjectFields (_ : Unit) : M FnBody :=
|
||||
let rec loop (usizeCount : Nat) (i : Nat) : M FnBody := do
|
||||
match args[i]? with
|
||||
| some (.fvar fvarId) =>
|
||||
match (← get).fvars[fvarId]? with
|
||||
| some (.var varId) =>
|
||||
match fields[i]! with
|
||||
| .usize .. =>
|
||||
let k ← loop (usizeCount + 1) (i + 1)
|
||||
return .uset objVar (ctorInfo.size + usizeCount) varId k
|
||||
| .scalar _ offset argType =>
|
||||
let k ← loop usizeCount (i + 1)
|
||||
return .sset objVar (ctorInfo.size + ctorInfo.usize) offset varId argType k
|
||||
| .object .. | .irrelevant => loop usizeCount (i + 1)
|
||||
| _ => loop usizeCount (i + 1)
|
||||
| some (.type _) | some .erased => loop usizeCount (i + 1)
|
||||
| none => lowerCode k
|
||||
loop 0 0
|
||||
return .vdecl objVar .object (.ctor ctorInfo objArgs) (← lowerNonObjectFields ())
|
||||
| some (.axiomInfo ..) =>
|
||||
if name == ``Quot.lcInv then
|
||||
match irArgs[2]! with
|
||||
@@ -295,7 +376,7 @@ partial def lowerLet (decl : LCNF.LetDecl) (k : LCNF.Code) : M FnBody := do
|
||||
partial def lowerAlt (discr : VarId) (a : LCNF.Alt) : M Alt := do
|
||||
match a with
|
||||
| .alt ctorName params code =>
|
||||
let ⟨ctorInfo, fields⟩ ← getCtorLayout ctorName
|
||||
let ⟨ctorInfo, fields⟩ ← getCtorInfo ctorName
|
||||
let lowerParams (params : Array LCNF.Param) (fields : Array CtorFieldInfo) : M FnBody := do
|
||||
let rec loop (i : Nat) : M FnBody := do
|
||||
match params[i]?, fields[i]? with
|
||||
@@ -320,7 +401,7 @@ partial def lowerAlt (discr : VarId) (a : LCNF.Alt) : M Alt := do
|
||||
end
|
||||
|
||||
def lowerResultType (type : Lean.Expr) (arity : Nat) : M IRType :=
|
||||
toIRType (resultTypeForArity type arity)
|
||||
lowerType (resultTypeForArity type arity)
|
||||
where resultTypeForArity (type : Lean.Expr) (arity : Nat) : Lean.Expr :=
|
||||
if arity == 0 then
|
||||
type
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.Environment
|
||||
import Lean.Compiler.IR.Format
|
||||
import Lean.Compiler.LCNF.CompilerM
|
||||
import Lean.Compiler.LCNF.MonoTypes
|
||||
import Lean.Compiler.LCNF.Types
|
||||
|
||||
namespace Lean
|
||||
namespace IR
|
||||
|
||||
open Lean.Compiler (LCNF.CacheExtension LCNF.isTypeFormerType LCNF.toLCNFType LCNF.toMonoType)
|
||||
|
||||
builtin_initialize irTypeExt : LCNF.CacheExtension Name IRType ←
|
||||
LCNF.CacheExtension.register
|
||||
|
||||
def nameToIRType (name : Name) : CoreM IRType := do
|
||||
match (← irTypeExt.find? name) with
|
||||
| some type => return type
|
||||
| none =>
|
||||
let type ← fillCache
|
||||
irTypeExt.insert name type
|
||||
return type
|
||||
where fillCache : CoreM IRType := do
|
||||
match name with
|
||||
| ``UInt8 => return .uint8
|
||||
| ``UInt16 => return .uint16
|
||||
| ``UInt32 => return .uint32
|
||||
| ``UInt64 => return .uint64
|
||||
| ``USize => return .usize
|
||||
| ``Float => return .float
|
||||
| ``Float32 => return .float32
|
||||
| ``lcErased => return .irrelevant
|
||||
| _ =>
|
||||
let env ← Lean.getEnv
|
||||
let some (.inductInfo inductiveVal) := env.find? name | return .object
|
||||
let ctorNames := inductiveVal.ctors
|
||||
let numCtors := ctorNames.length
|
||||
for ctorName in ctorNames do
|
||||
let some (.ctorInfo ctorInfo) := env.find? ctorName | unreachable!
|
||||
let isRelevant ← Meta.MetaM.run' <|
|
||||
Meta.forallTelescopeReducing ctorInfo.type fun params _ => do
|
||||
for field in params[ctorInfo.numParams...*] do
|
||||
let fieldType ← field.fvarId!.getType
|
||||
let lcnfFieldType ← LCNF.toLCNFType fieldType
|
||||
let monoFieldType ← LCNF.toMonoType lcnfFieldType
|
||||
if !monoFieldType.isErased then return true
|
||||
return false
|
||||
if isRelevant then return .object
|
||||
return if numCtors == 1 then
|
||||
.object
|
||||
else if numCtors < Nat.pow 2 8 then
|
||||
.uint8
|
||||
else if numCtors < Nat.pow 2 16 then
|
||||
.uint16
|
||||
else if numCtors < Nat.pow 2 32 then
|
||||
.uint32
|
||||
else
|
||||
.object
|
||||
|
||||
def toIRType (type : Lean.Expr) : CoreM IRType := do
|
||||
match type with
|
||||
| .const name _ => nameToIRType name
|
||||
| .app .. =>
|
||||
-- All mono types are in headBeta form.
|
||||
let .const name _ := type.getAppFn | unreachable!
|
||||
nameToIRType name
|
||||
| .forallE .. => return .object
|
||||
| _ => unreachable!
|
||||
|
||||
inductive CtorFieldInfo where
|
||||
| irrelevant
|
||||
| object (i : Nat)
|
||||
| usize (i : Nat)
|
||||
| scalar (sz : Nat) (offset : Nat) (type : IRType)
|
||||
deriving Inhabited
|
||||
|
||||
namespace CtorFieldInfo
|
||||
|
||||
def format : CtorFieldInfo → Format
|
||||
| irrelevant => "◾"
|
||||
| object i => f!"obj@{i}"
|
||||
| usize i => f!"usize@{i}"
|
||||
| scalar sz offset type => f!"scalar#{sz}@{offset}:{type}"
|
||||
|
||||
instance : ToFormat CtorFieldInfo := ⟨format⟩
|
||||
|
||||
end CtorFieldInfo
|
||||
|
||||
structure CtorLayout where
|
||||
ctorInfo : CtorInfo
|
||||
fieldInfo : Array CtorFieldInfo
|
||||
deriving Inhabited
|
||||
|
||||
builtin_initialize ctorLayoutExt : LCNF.CacheExtension Name CtorLayout ←
|
||||
LCNF.CacheExtension.register
|
||||
|
||||
def getCtorLayout (ctorName : Name) : CoreM CtorLayout := do
|
||||
match (← ctorLayoutExt.find? ctorName) with
|
||||
| some info => return info
|
||||
| none =>
|
||||
let info ← fillCache
|
||||
ctorLayoutExt.insert ctorName info
|
||||
return info
|
||||
where fillCache := do
|
||||
let .some (.ctorInfo ctorInfo) := (← getEnv).find? ctorName | unreachable!
|
||||
Meta.MetaM.run' <| Meta.forallTelescopeReducing ctorInfo.type fun params _ => do
|
||||
let mut fields : Array CtorFieldInfo := .emptyWithCapacity ctorInfo.numFields
|
||||
let mut nextIdx := 0
|
||||
let mut has1BScalar := false
|
||||
let mut has2BScalar := false
|
||||
let mut has4BScalar := false
|
||||
let mut has8BScalar := false
|
||||
for field in params[ctorInfo.numParams...(ctorInfo.numParams + ctorInfo.numFields)] do
|
||||
let fieldType ← field.fvarId!.getType
|
||||
let lcnfFieldType ← LCNF.toLCNFType fieldType
|
||||
let monoFieldType ← LCNF.toMonoType lcnfFieldType
|
||||
let ctorField ← match (← toIRType monoFieldType) with
|
||||
| .object | .tobject => do
|
||||
let i := nextIdx
|
||||
nextIdx := nextIdx + 1
|
||||
pure <| .object i
|
||||
| .usize => pure <| .usize 0
|
||||
| .irrelevant => .pure <| .irrelevant
|
||||
| .uint8 =>
|
||||
has1BScalar := true
|
||||
.pure <| .scalar 1 0 .uint8
|
||||
| .uint16 =>
|
||||
has2BScalar := true
|
||||
.pure <| .scalar 2 0 .uint16
|
||||
| .uint32 =>
|
||||
has4BScalar := true
|
||||
.pure <| .scalar 4 0 .uint32
|
||||
| .uint64 =>
|
||||
has8BScalar := true
|
||||
.pure <| .scalar 8 0 .uint64
|
||||
| .float32 =>
|
||||
has4BScalar := true
|
||||
.pure <| .scalar 4 0 .float32
|
||||
| .float =>
|
||||
has8BScalar := true
|
||||
.pure <| .scalar 8 0 .float
|
||||
| .struct .. | .union .. => unreachable!
|
||||
fields := fields.push ctorField
|
||||
let numObjs := nextIdx
|
||||
⟨fields, nextIdx⟩ := Id.run <| StateT.run (s := nextIdx) <| fields.mapM fun field => do
|
||||
match field with
|
||||
| .usize _ => do
|
||||
let i ← modifyGet fun nextIdx => (nextIdx, nextIdx + 1)
|
||||
return .usize i
|
||||
| .object _ | .scalar .. | .irrelevant => return field
|
||||
let numUSize := nextIdx - numObjs
|
||||
let adjustScalarsForSize (fields : Array CtorFieldInfo) (size : Nat) (nextOffset : Nat)
|
||||
: Array CtorFieldInfo × Nat :=
|
||||
Id.run <| StateT.run (s := nextOffset) <| fields.mapM fun field => do
|
||||
match field with
|
||||
| .scalar sz _ type => do
|
||||
if sz == size then
|
||||
let offset ← modifyGet fun nextOffset => (nextOffset, nextOffset + sz)
|
||||
return .scalar sz offset type
|
||||
else
|
||||
return field
|
||||
| .object _ | .usize _ | .irrelevant => return field
|
||||
let mut nextOffset := 0
|
||||
if has8BScalar then
|
||||
⟨fields, nextOffset⟩ := adjustScalarsForSize fields 8 nextOffset
|
||||
if has4BScalar then
|
||||
⟨fields, nextOffset⟩ := adjustScalarsForSize fields 4 nextOffset
|
||||
if has2BScalar then
|
||||
⟨fields, nextOffset⟩ := adjustScalarsForSize fields 2 nextOffset
|
||||
if has1BScalar then
|
||||
⟨fields, nextOffset⟩ := adjustScalarsForSize fields 1 nextOffset
|
||||
return {
|
||||
ctorInfo := {
|
||||
name := ctorName
|
||||
cidx := ctorInfo.cidx
|
||||
size := numObjs
|
||||
usize := numUSize
|
||||
ssize := nextOffset
|
||||
}
|
||||
fieldInfo := fields
|
||||
}
|
||||
|
||||
end IR
|
||||
end Lean
|
||||
@@ -648,20 +648,16 @@ def hasLocalInst (type : Expr) : Bool :=
|
||||
/--
|
||||
Return `true` if `decl` is supposed to be inlined/specialized.
|
||||
-/
|
||||
def Decl.isTemplateLikeCore (env : Environment) (decl : Decl) : Bool := Id.run do
|
||||
def Decl.isTemplateLike (decl : Decl) : CoreM Bool := do
|
||||
if hasLocalInst decl.type then
|
||||
return true -- `decl` applications will be specialized
|
||||
else if Meta.isInstanceCore env decl.name then
|
||||
else if (← Meta.isInstance decl.name) then
|
||||
return true -- `decl` is "fuel" for code specialization
|
||||
else if decl.inlineable || hasSpecializeAttribute env decl.name then
|
||||
else if decl.inlineable || hasSpecializeAttribute (← getEnv) decl.name then
|
||||
return true -- `decl` is going to be inlined or specialized
|
||||
else
|
||||
return false
|
||||
|
||||
@[inherit_doc Decl.isTemplateLikeCore]
|
||||
def Decl.isTemplateLike (decl : Decl) : CoreM Bool :=
|
||||
return decl.isTemplateLikeCore (← getEnv)
|
||||
|
||||
private partial def collectType (e : Expr) : FVarIdHashSet → FVarIdHashSet :=
|
||||
match e with
|
||||
| .forallE _ d b _ => collectType b ∘ collectType d
|
||||
|
||||
@@ -33,17 +33,7 @@ def mkDeclExt (name : Name := by exact decl_name%) : IO DeclExt :=
|
||||
mkInitial := pure {},
|
||||
addImportedFn := fun _ => pure {},
|
||||
addEntryFn := fun s decl => s.insert decl.name decl
|
||||
exportEntriesFnEx env s level := Id.run do
|
||||
let mut entries := sortedDecls s
|
||||
if level != .private then
|
||||
entries := entries.map fun decl =>
|
||||
if decl.isTemplateLikeCore env then
|
||||
-- ensure templates are available to downstream modules
|
||||
decl
|
||||
else
|
||||
-- hide body but not signature
|
||||
{ decl with value := .extern { arity? := decl.getArity, entries := [.opaque decl.name] } }
|
||||
return entries
|
||||
exportEntriesFn := sortedDecls
|
||||
statsFn := fun s =>
|
||||
let numEntries := s.foldl (init := 0) (fun count _ _ => count + 1)
|
||||
format "number of local entries: " ++ format numEntries
|
||||
|
||||
@@ -51,23 +51,16 @@ def inlineCandidate? (e : LetValue) : SimpM (Option InlineCandidateInfo) := do
|
||||
We don't inline instances tagged with `[inline]/[always_inline]/[inline_if_reduce]` at the base phase
|
||||
We assume that at the base phase these annotations are for the instance methods that have been lambda lifted.
|
||||
-/
|
||||
if (← inBasePhase) then
|
||||
if (← Meta.isInstance decl.name) then
|
||||
unless decl.name == ``instDecidableEqBool do
|
||||
/-
|
||||
TODO: remove this hack after we refactor `Decidable` as suggested by Gabriel.
|
||||
Recall that the current `Decidable` class is special case since it is an inductive datatype which is not a
|
||||
structure like all other type classes. This is bad since it prevents us from treating all classes in a uniform
|
||||
way. After we change `Decidable` to a structure as suggested by Gabriel, we should only accept type classes
|
||||
that are structures. Moreover, we should reject instances that have only one exit point producing an explicit structure.
|
||||
-/
|
||||
return false
|
||||
-- This is done to avoid inlining `_override` implementations for computed fields in the
|
||||
-- base phase, since `cases` constructs have not yet been replaced by their underlying
|
||||
-- implementation, and thus inlining `_override` implementations for computed fields will
|
||||
-- expose a constructor/`cases` mismatch.
|
||||
-- TODO: Find a better solution for this problem.
|
||||
if decl.name matches .str _ "_override" then return false
|
||||
if (← inBasePhase <&&> Meta.isInstance decl.name) then
|
||||
unless decl.name == ``instDecidableEqBool do
|
||||
/-
|
||||
TODO: remove this hack after we refactor `Decidable` as suggested by Gabriel.
|
||||
Recall that the current `Decidable` class is special case since it is an inductive datatype which is not a
|
||||
structure like all other type classes. This is bad since it prevents us from treating all classes in a uniform
|
||||
way. After we change `Decidable` to a structure as suggested by Gabriel, we should only accept type classes
|
||||
that are structures. Moreover, we should reject instances that have only one exit point producing an explicit structure.
|
||||
-/
|
||||
return false
|
||||
if decl.alwaysInlineAttr then return true
|
||||
-- TODO: check inlining quota
|
||||
if decl.inlineAttr || decl.inlineIfReduceAttr then return true
|
||||
|
||||
@@ -189,11 +189,7 @@ def saveSpecParamInfo (decls : Array Decl) : CompilerM Unit := do
|
||||
let mut paramsInfo := declsInfo[i]!
|
||||
let some mask := m.find? decl.name | unreachable!
|
||||
trace[Compiler.specialize.info] "{decl.name} {mask}"
|
||||
paramsInfo := Array.zipWith (as := paramsInfo) (bs := mask) fun info fixed =>
|
||||
if fixed || info matches .user then
|
||||
info
|
||||
else
|
||||
.other
|
||||
paramsInfo := Array.zipWith (fun info fixed => if fixed || info matches .user then info else .other) paramsInfo mask
|
||||
for j in [:paramsInfo.size] do
|
||||
let mut info := paramsInfo[j]!
|
||||
if info matches .fixedNeutral && !hasFwdDeps decl paramsInfo j then
|
||||
|
||||
@@ -679,7 +679,9 @@ where
|
||||
visit (f.beta e.getAppArgs)
|
||||
|
||||
visitApp (e : Expr) : M Arg := do
|
||||
if let .const declName us := CSimp.replaceConstants (← getEnv) e.getAppFn then
|
||||
if let some (args, n, t, v, b) := e.letFunAppArgs? then
|
||||
visitCore <| mkAppN (.letE n t v b (nondep := true)) args
|
||||
else if let .const declName us := CSimp.replaceConstants (← getEnv) e.getAppFn then
|
||||
if declName == ``Quot.lift then
|
||||
visitQuotLift e
|
||||
else if declName == ``Quot.mk then
|
||||
|
||||
@@ -718,14 +718,9 @@ where doCompile := do
|
||||
return
|
||||
let opts ← getOptions
|
||||
if compiler.enableNew.get opts then
|
||||
withoutExporting do
|
||||
let state ← Core.saveState
|
||||
try
|
||||
compileDeclsNew decls
|
||||
catch e =>
|
||||
state.restore
|
||||
if logErrors then
|
||||
throw e
|
||||
withoutExporting
|
||||
try compileDeclsNew decls catch e =>
|
||||
if logErrors then throw e else return ()
|
||||
else
|
||||
let res ← withTraceNode `compiler (fun _ => return m!"compiling old: {decls}") do
|
||||
return compileDeclsOld (← getEnv) opts decls
|
||||
|
||||
@@ -932,10 +932,7 @@ def elabLetDeclCore (stx : Syntax) (expectedType? : Option Expr) (initConfig : L
|
||||
fun stx expectedType? => elabLetDeclCore stx expectedType? { nondep := true }
|
||||
|
||||
@[builtin_term_elab «let_fun»] def elabLetFunDecl : TermElab :=
|
||||
fun stx expectedType? => do
|
||||
withRef stx <| Linter.logLintIf Linter.linter.deprecated stx[0]
|
||||
"`let_fun` has been deprecated in favor of `have`"
|
||||
elabLetDeclCore stx expectedType? { nondep := true }
|
||||
fun stx expectedType? => elabLetDeclCore stx expectedType? { nondep := true }
|
||||
|
||||
@[builtin_term_elab «let_delayed»] def elabLetDelayedDecl : TermElab :=
|
||||
fun stx expectedType? => elabLetDeclCore stx expectedType? { postponeValue := true }
|
||||
|
||||
@@ -108,7 +108,7 @@ open Meta
|
||||
Recall that we do not use the same approach used to elaborate type ascriptions.
|
||||
For the `($val : $type)` notation, we just elaborate `val` using `type` and
|
||||
ensure it has type `type`. This approach only ensure the type resulting expression
|
||||
is definitionally equal to `type`. For the `show` notation we use `have` to ensure the type
|
||||
is definitionally equal to `type`. For the `show` notation we use `let_fun` to ensure the type
|
||||
of the resulting expression is *structurally equal* `type`. Structural equality is important,
|
||||
for example, if the resulting expression is a `simp`/`rw` parameter. Here is an example:
|
||||
```
|
||||
|
||||
@@ -67,12 +67,11 @@ def DerivingHandler := (typeNames : Array Name) → CommandElabM Bool
|
||||
|
||||
builtin_initialize derivingHandlersRef : IO.Ref (NameMap (List DerivingHandler)) ← IO.mkRef {}
|
||||
|
||||
/--
|
||||
Registers a deriving handler for a class. This function should be called in an `initialize` block.
|
||||
/-- A `DerivingHandler` is called on the fully qualified names of all types it is running for
|
||||
as well as the syntax of a `with` argument, if present.
|
||||
|
||||
A `DerivingHandler` is called on the fully qualified names of all types it is running for. For
|
||||
example, `deriving instance Foo for Bar, Baz` invokes ``fooHandler #[`Bar, `Baz]``.
|
||||
-/
|
||||
For example, `deriving instance Foo with fooArgs for Bar, Baz` invokes
|
||||
``fooHandler #[`Bar, `Baz] `(fooArgs)``. -/
|
||||
def registerDerivingHandler (className : Name) (handler : DerivingHandler) : IO Unit := do
|
||||
unless (← initializing) do
|
||||
throw (IO.userError "failed to register deriving handler, it can only be registered during initialization")
|
||||
|
||||
@@ -1156,7 +1156,6 @@ where
|
||||
finishElab headers
|
||||
processDeriving headers
|
||||
elabAsync header view declId := do
|
||||
assert! view.kind.isTheorem
|
||||
let env ← getEnv
|
||||
let async ← env.addConstAsync declId.declName .thm
|
||||
(exportedKind? := guard (!isPrivateName declId.declName) *> some .axiom)
|
||||
@@ -1179,12 +1178,6 @@ where
|
||||
s := collectLevelParams s type
|
||||
let scopeLevelNames ← getLevelNames
|
||||
let levelParams ← IO.ofExcept <| sortDeclLevelParams scopeLevelNames allUserLevelNames s.params
|
||||
|
||||
let type ← if cleanup.letToHave.get (← getOptions) then
|
||||
withRef header.declId <| Meta.letToHave type
|
||||
else
|
||||
pure type
|
||||
|
||||
async.commitSignature { name := header.declName, levelParams, type }
|
||||
|
||||
-- attributes should be applied on the main thread; see below
|
||||
|
||||
@@ -13,7 +13,6 @@ import Lean.Util.NumApps
|
||||
import Lean.Meta.AbstractNestedProofs
|
||||
import Lean.Meta.ForEachExpr
|
||||
import Lean.Meta.Eqns
|
||||
import Lean.Meta.LetToHave
|
||||
import Lean.Elab.RecAppSyntax
|
||||
import Lean.Elab.DefView
|
||||
import Lean.Elab.PreDefinition.TerminationHint
|
||||
@@ -22,11 +21,6 @@ namespace Lean.Elab
|
||||
open Meta
|
||||
open Term
|
||||
|
||||
register_builtin_option cleanup.letToHave : Bool := {
|
||||
defValue := true
|
||||
descr := "Enables transforming `let`s to `have`s after elaborating declarations."
|
||||
}
|
||||
|
||||
/--
|
||||
A (potentially recursive) definition.
|
||||
The elaborator converts it into Kernel definitions using many different strategies.
|
||||
@@ -94,31 +88,6 @@ def applyAttributesOf (preDefs : Array PreDefinition) (applicationTime : Attribu
|
||||
for preDef in preDefs do
|
||||
applyAttributesAt preDef.declName preDef.modifiers.attrs applicationTime
|
||||
|
||||
/--
|
||||
Applies `Meta.letToHave` to the values of defs, instances, and abbrevs.
|
||||
Does not apply the transformation to values that are proofs, or to unsafe definitions.
|
||||
-/
|
||||
def letToHaveValue (preDef : PreDefinition) : MetaM PreDefinition := withRef preDef.ref do
|
||||
if !cleanup.letToHave.get (← getOptions)
|
||||
|| preDef.modifiers.isUnsafe
|
||||
|| preDef.kind matches .theorem | .example | .opaque then
|
||||
return preDef
|
||||
else if ← Meta.isProp preDef.type then
|
||||
return preDef
|
||||
else
|
||||
let value ← Meta.letToHave preDef.value
|
||||
return { preDef with value }
|
||||
|
||||
/--
|
||||
Applies `Meta.letToHave` to the type of the predef.
|
||||
-/
|
||||
def letToHaveType (preDef : PreDefinition) : MetaM PreDefinition := withRef preDef.ref do
|
||||
if !cleanup.letToHave.get (← getOptions) || preDef.kind matches .example then
|
||||
return preDef
|
||||
else
|
||||
let type ← Meta.letToHave preDef.type
|
||||
return { preDef with type }
|
||||
|
||||
def abstractNestedProofs (preDef : PreDefinition) (cache := true) : MetaM PreDefinition := withRef preDef.ref do
|
||||
if preDef.kind.isTheorem || preDef.kind.isExample then
|
||||
pure preDef
|
||||
@@ -169,11 +138,9 @@ private def checkMeta (preDef : PreDefinition) : TermElabM Unit := do
|
||||
| _, _ => pure ()
|
||||
return true
|
||||
|
||||
private def addNonRecAux (preDef : PreDefinition) (compile : Bool) (all : List Name) (applyAttrAfterCompilation := true) (cacheProofs := true) (cleanupValue := false) : TermElabM Unit :=
|
||||
private def addNonRecAux (preDef : PreDefinition) (compile : Bool) (all : List Name) (applyAttrAfterCompilation := true) (cacheProofs := true) : TermElabM Unit :=
|
||||
withRef preDef.ref do
|
||||
let preDef ← abstractNestedProofs (cache := cacheProofs) preDef
|
||||
let preDef ← letToHaveType preDef
|
||||
let preDef ← if cleanupValue then letToHaveValue preDef else pure preDef
|
||||
let mkDefDecl : TermElabM Declaration :=
|
||||
return Declaration.defnDecl {
|
||||
name := preDef.declName, levelParams := preDef.levelParams, type := preDef.type, value := preDef.value
|
||||
@@ -218,11 +185,11 @@ private def addNonRecAux (preDef : PreDefinition) (compile : Bool) (all : List N
|
||||
generateEagerEqns preDef.declName
|
||||
applyAttributesOf #[preDef] AttributeApplicationTime.afterCompilation
|
||||
|
||||
def addAndCompileNonRec (preDef : PreDefinition) (all : List Name := [preDef.declName]) (cleanupValue := false) : TermElabM Unit := do
|
||||
addNonRecAux preDef (compile := true) (all := all) (cleanupValue := cleanupValue)
|
||||
def addAndCompileNonRec (preDef : PreDefinition) (all : List Name := [preDef.declName]) : TermElabM Unit := do
|
||||
addNonRecAux preDef (compile := true) (all := all)
|
||||
|
||||
def addNonRec (preDef : PreDefinition) (applyAttrAfterCompilation := true) (all : List Name := [preDef.declName]) (cacheProofs := true) (cleanupValue := false) : TermElabM Unit := do
|
||||
addNonRecAux preDef (compile := false) (applyAttrAfterCompilation := applyAttrAfterCompilation) (all := all) (cacheProofs := cacheProofs) (cleanupValue := cleanupValue)
|
||||
def addNonRec (preDef : PreDefinition) (applyAttrAfterCompilation := true) (all : List Name := [preDef.declName]) (cacheProofs := true) : TermElabM Unit := do
|
||||
addNonRecAux preDef (compile := false) (applyAttrAfterCompilation := applyAttrAfterCompilation) (all := all) (cacheProofs := cacheProofs)
|
||||
|
||||
/--
|
||||
Eliminate recursive application annotations containing syntax. These annotations are used by the well-founded recursion module
|
||||
|
||||
@@ -25,14 +25,18 @@ structure EqnInfoCore where
|
||||
deriving Inhabited
|
||||
|
||||
/--
|
||||
Zeta reduces `let` and `have` while consuming metadata.
|
||||
Zeta reduces `let` and `let_fun` while consuming metadata.
|
||||
Returns true if progress is made.
|
||||
-/
|
||||
partial def expand (progress : Bool) (e : Expr) : Bool × Expr :=
|
||||
match e with
|
||||
| Expr.letE _ _ v b _ => expand true (b.instantiate1 v)
|
||||
| Expr.mdata _ b => expand true b
|
||||
| e => (progress, e)
|
||||
| e =>
|
||||
if let some (_, _, v, b) := e.letFun? then
|
||||
expand true (b.instantiate1 v)
|
||||
else
|
||||
(progress, e)
|
||||
|
||||
def expandRHS? (mvarId : MVarId) : MetaM (Option MVarId) := do
|
||||
let target ← mvarId.getType'
|
||||
|
||||
@@ -98,7 +98,11 @@ private partial def ensureNoUnassignedLevelMVarsAtPreDef (preDef : PreDefinition
|
||||
| .proj _ _ b => withExpr e do visit b
|
||||
| .sort u => visitLevel u (← read)
|
||||
| .const _ us => (if head then id else withExpr e) <| us.forM (visitLevel · (← read))
|
||||
| .app .. => withExpr e do e.withApp fun f args => do visit f true; args.forM visit
|
||||
| .app .. => withExpr e do
|
||||
if let some (args, n, t, v, b) := e.letFunAppArgs? then
|
||||
visit t; visit v; withLocalDeclD n t fun x => visit (b.instantiate1 x); args.forM visit
|
||||
else
|
||||
e.withApp fun f args => do visit f true; args.forM visit
|
||||
| _ => pure ()
|
||||
try
|
||||
visit preDef.value |>.run preDef.value |>.run {}
|
||||
@@ -315,9 +319,9 @@ def addPreDefinitions (preDefs : Array PreDefinition) : TermElabM Unit := withLC
|
||||
let preDef ← eraseRecAppSyntax preDefs[0]!
|
||||
ensureEqnReservedNamesAvailable preDef.declName
|
||||
if preDef.modifiers.isNoncomputable then
|
||||
addNonRec preDef (cleanupValue := true)
|
||||
addNonRec preDef
|
||||
else
|
||||
addAndCompileNonRec preDef (cleanupValue := true)
|
||||
addAndCompileNonRec preDef
|
||||
preDef.termination.ensureNone "not recursive"
|
||||
else if preDefs.any (·.modifiers.isUnsafe) then
|
||||
addAndCompileUnsafe preDefs
|
||||
|
||||
@@ -97,7 +97,6 @@ where
|
||||
catch e =>
|
||||
throwError "failed to generate unfold theorem for '{declName}':\n{e.toMessageData}"
|
||||
let type ← mkForallFVars xs type
|
||||
let type ← letToHave type
|
||||
let value ← mkLambdaFVars xs goal
|
||||
addDecl <| Declaration.thmDecl {
|
||||
name, type, value
|
||||
|
||||
@@ -93,7 +93,6 @@ where
|
||||
doRealize name type := withOptions (tactic.hygienic.set · false) do
|
||||
let value ← mkProof info.declName type
|
||||
let (type, value) ← removeUnusedEqnHypotheses type value
|
||||
let type ← letToHave type
|
||||
addDecl <| Declaration.thmDecl {
|
||||
name, type, value
|
||||
levelParams := info.levelParams
|
||||
@@ -127,7 +126,6 @@ where
|
||||
let goal ← mkFreshExprSyntheticOpaqueMVar type
|
||||
mkUnfoldProof declName goal.mvarId!
|
||||
let type ← mkForallFVars xs type
|
||||
let type ← letToHave type
|
||||
let value ← mkLambdaFVars xs (← instantiateMVars goal)
|
||||
addDecl <| Declaration.thmDecl {
|
||||
name, type, value
|
||||
|
||||
@@ -66,6 +66,6 @@ partial def addSmartUnfoldingDef (preDef : PreDefinition) (recArgPos : Nat) : Te
|
||||
else
|
||||
withEnableInfoTree false do
|
||||
let preDefSUnfold ← addSmartUnfoldingDefAux preDef recArgPos
|
||||
addNonRec preDefSUnfold (cleanupValue := true)
|
||||
addNonRec preDefSUnfold
|
||||
|
||||
end Lean.Elab.Structural
|
||||
|
||||
@@ -23,7 +23,6 @@ Preprocesses the expressions to improve the effectiveness of `wfRecursion`.
|
||||
|
||||
Unlike `Lean.Elab.Structural.preprocess`, do _not_ beta-reduce, as it could
|
||||
remove `let_fun`-lambdas that contain explicit termination proofs.
|
||||
(Note(kmill): this last statement no longer affects `let_fun`/`have`.)
|
||||
-/
|
||||
def floatRecApp (e : Expr) : CoreM Expr :=
|
||||
Core.transform e
|
||||
|
||||
@@ -91,7 +91,6 @@ def mkUnfoldEq (preDef : PreDefinition) (unaryPreDefName : Name) (wfPreprocessPr
|
||||
|
||||
let value ← instantiateMVars main
|
||||
let type ← mkForallFVars xs type
|
||||
let type ← letToHave type
|
||||
let value ← mkLambdaFVars xs value
|
||||
addDecl <| Declaration.thmDecl {
|
||||
name, type, value
|
||||
@@ -124,7 +123,6 @@ def mkBinaryUnfoldEq (preDef : PreDefinition) (unaryPreDefName : Name) : MetaM U
|
||||
|
||||
let value ← instantiateMVars main
|
||||
let type ← mkForallFVars xs type
|
||||
let type ← letToHave type
|
||||
let value ← mkLambdaFVars xs value
|
||||
addDecl <| Declaration.thmDecl {
|
||||
name, type, value
|
||||
|
||||
@@ -1155,11 +1155,12 @@ private partial def mkFlatCtor (levelParams : List Name) (params : Array Expr) (
|
||||
let ctor := getStructureCtor env structName
|
||||
let val ← mkFlatCtorExpr levelParams params ctor replaceIndFVars
|
||||
withLCtx {} {} do trace[Elab.structure] "created flat constructor:{indentExpr val}"
|
||||
-- Note: flatCtorName will be private if the constructor is private
|
||||
let flatCtorName := mkFlatCtorOfStructCtorName ctor.name
|
||||
let valType ← replaceIndFVars (← instantiateMVars (← inferType val))
|
||||
let valType := valType.inferImplicit params.size true
|
||||
addDecl <| Declaration.defnDecl (← mkDefinitionValInferrringUnsafe flatCtorName levelParams valType val .abbrev)
|
||||
unless val.hasSyntheticSorry do
|
||||
-- Note: flatCtorName will be private if the constructor is private
|
||||
let flatCtorName := mkFlatCtorOfStructCtorName ctor.name
|
||||
let valType ← replaceIndFVars (← instantiateMVars (← inferType val))
|
||||
let valType := valType.inferImplicit params.size true
|
||||
addDecl <| Declaration.defnDecl (← mkDefinitionValInferrringUnsafe flatCtorName levelParams valType val .abbrev)
|
||||
|
||||
private partial def checkResultingUniversesForFields (fieldInfos : Array StructFieldInfo) (u : Level) : TermElabM Unit := do
|
||||
for info in fieldInfos do
|
||||
@@ -1441,16 +1442,13 @@ def elabStructureCommand : InductiveElabDescr where
|
||||
finalizeTermElab := withLCtx lctx localInsts do checkDefaults fieldInfos
|
||||
prefinalize := fun levelParams params replaceIndFVars => do
|
||||
withLCtx lctx localInsts do
|
||||
withOptions (warn.sorry.set · false) do
|
||||
addProjections params r fieldInfos
|
||||
addProjections params r fieldInfos
|
||||
registerStructure view.declName fieldInfos
|
||||
runStructElabM (init := state) do
|
||||
withOptions (warn.sorry.set · false) do
|
||||
mkFlatCtor levelParams params view.declName replaceIndFVars
|
||||
mkFlatCtor levelParams params view.declName replaceIndFVars
|
||||
addDefaults levelParams params replaceIndFVars
|
||||
let parentInfos ← withLCtx lctx localInsts <| runStructElabM (init := state) do
|
||||
withOptions (warn.sorry.set · false) do
|
||||
mkRemainingProjections levelParams params view
|
||||
mkRemainingProjections levelParams params view
|
||||
setStructureParents view.declName parentInfos
|
||||
withSaveInfoContext do -- save new env
|
||||
for field in view.fields do
|
||||
|
||||
@@ -114,11 +114,8 @@ partial def dischargeFailEntails (ps : Expr) (Q : Expr) (Q' : Expr) (goalTag : N
|
||||
end
|
||||
|
||||
def dischargeMGoal (goal : MGoal) (goalTag : Name) : n Expr := do
|
||||
liftMetaM <| do trace[Elab.Tactic.Do.spec] "dischargeMGoal: {(← reduceProj? goal.target).getD goal.target}"
|
||||
-- controlAt MetaM (fun map => do trace[Elab.Tactic.Do.spec] "dischargeMGoal: {(← reduceProj? goal.target).getD goal.target}"; map (pure ()))
|
||||
-- simply try one of the assumptions for now. Later on we might want to decompose conjunctions etc; full xsimpl
|
||||
-- The `withDefault` ensures that a hyp `⌜s = 4⌝` can be used to discharge `⌜s = 4⌝ s`.
|
||||
-- (Recall that `⌜s = 4⌝ s` is `SVal.curry (σs:=[Nat]) (fun _ => s = 4) s` and `SVal.curry` is
|
||||
-- semi-reducible.)
|
||||
let some prf ← liftMetaM goal.assumption | mkFreshExprSyntheticOpaqueMVar goal.toExpr goalTag
|
||||
return prf
|
||||
|
||||
@@ -179,7 +176,7 @@ def mSpec (goal : MGoal) (elabSpecAtWP : Expr → n SpecTheorem) (goalTag : Name
|
||||
-- Often P or Q are schematic (i.e. an MVar app). Try to solve by rfl.
|
||||
-- We do `fullApproxDefEq` here so that `constApprox` is active; this is useful in
|
||||
-- `need_const_approx` of `doLogicTests.lean`.
|
||||
let (HPRfl, QQ'Rfl) ← withAssignableSyntheticOpaque <| fullApproxDefEq <| do
|
||||
let (HPRfl, QQ'Rfl) ← withDefault <| withAssignableSyntheticOpaque <| fullApproxDefEq <| do
|
||||
return (← isDefEqGuarded P goal.hyps, ← isDefEqGuarded Q Q')
|
||||
|
||||
-- Discharge the validity proof for the spec if not rfl
|
||||
|
||||
@@ -350,7 +350,7 @@ where
|
||||
try
|
||||
let specThm ← findSpec ctx.specThms wp
|
||||
trace[Elab.Tactic.Do.vcgen] "Candidate spec for {f.constName!}: {specThm.proof}"
|
||||
let (prf, specHoles) ← withDefault <| mSpec goal (fun _wp => return specThm) name
|
||||
let (prf, specHoles) ← mSpec goal (fun _wp => return specThm) name
|
||||
assignMVars specHoles
|
||||
return prf
|
||||
catch ex =>
|
||||
|
||||
@@ -111,7 +111,7 @@ def solveMonoStep (failK : ∀ {α}, Expr → Array Name → MetaM α := @defaul
|
||||
return [goal]
|
||||
|
||||
match_expr type with
|
||||
| monotone α inst_α _ _ f =>
|
||||
| monotone α inst_α β inst_β f =>
|
||||
-- Ensure f is not headed by a redex and headed by at least one lambda, and clean some
|
||||
-- redexes left by some of the lemmas we tend to apply
|
||||
let f ← instantiateMVars f
|
||||
@@ -150,6 +150,26 @@ def solveMonoStep (failK : ∀ {α}, Expr → Array Name → MetaM α := @defaul
|
||||
pure goal'
|
||||
return [goal'.mvarId!]
|
||||
|
||||
-- Float `letFun` to the environment.
|
||||
-- (cannot use `applyConst`, it tends to reduce the let redex)
|
||||
match_expr e with
|
||||
| letFun γ _ v b =>
|
||||
if γ.hasLooseBVars || v.hasLooseBVars then
|
||||
failK f #[]
|
||||
let b' := f.updateLambdaE! f.bindingDomain! b
|
||||
let p ← mkAppOptM ``monotone_letFun #[α, β, γ, inst_α, inst_β, v, b']
|
||||
let new_goals ← prependError m!"Could not apply {p}:" do
|
||||
goal.apply p
|
||||
let [new_goal] := new_goals
|
||||
| throwError "Unexpected number of goals after {.ofConstName ``monotone_letFun}."
|
||||
let (_, new_goal) ←
|
||||
if b.isLambda then
|
||||
new_goal.intro b.bindingName!
|
||||
else
|
||||
new_goal.intro1
|
||||
return [new_goal]
|
||||
| _ => pure ()
|
||||
|
||||
-- Handle lambdas, preserving the name of the binder
|
||||
if e.isLambda then
|
||||
let [new_goal] ← applyConst goal ``monotone_of_monotone_apply
|
||||
|
||||
@@ -25,7 +25,7 @@ def reverseDuplicate (xs : List α) :=
|
||||
.reverse (xs ++ xs)
|
||||
```
|
||||
```output
|
||||
Invalid dotted identifier notation: The expected type of `.reverse` could not be determined
|
||||
Invalid dotted identifier notation: The type of `.reverse` could not be determined
|
||||
```
|
||||
```lean fixed
|
||||
def reverseDuplicate (xs : List α) : List α :=
|
||||
|
||||
@@ -1963,11 +1963,10 @@ def setAppPPExplicitForExposingMVars (e : Expr) : Expr :=
|
||||
| _ => e
|
||||
|
||||
/--
|
||||
Returns true if `e` is an expression of the form `letFun v f`.
|
||||
Returns true if `e` is a `let_fun` expression, which is an expression of the form `letFun v f`.
|
||||
Ideally `f` is a lambda, but we do not require that here.
|
||||
Warning: if the `let_fun` is applied to additional arguments (such as in `(let_fun f := id; id) 1`), this function returns `false`.
|
||||
-/
|
||||
@[deprecated Expr.isHave (since := "2025-06-29")]
|
||||
def isLetFun (e : Expr) : Bool := e.isAppOfArity ``letFun 4
|
||||
|
||||
/--
|
||||
@@ -1980,7 +1979,6 @@ They can be created using `Lean.Meta.mkLetFun`.
|
||||
|
||||
If in the encoding of `let_fun` the last argument to `letFun` is eta reduced, this returns `Name.anonymous` for the binder name.
|
||||
-/
|
||||
@[deprecated Expr.isHave (since := "2025-06-29")]
|
||||
def letFun? (e : Expr) : Option (Name × Expr × Expr × Expr) :=
|
||||
match e with
|
||||
| .app (.app (.app (.app (.const ``letFun _) t) _β) v) f =>
|
||||
@@ -1993,7 +1991,6 @@ def letFun? (e : Expr) : Option (Name × Expr × Expr × Expr) :=
|
||||
Like `Lean.Expr.letFun?`, but handles the case when the `let_fun` expression is possibly applied to additional arguments.
|
||||
Returns those arguments in addition to the values returned by `letFun?`.
|
||||
-/
|
||||
@[deprecated Expr.isHave (since := "2025-06-29")]
|
||||
def letFunAppArgs? (e : Expr) : Option (Array Expr × Name × Expr × Expr × Expr) := do
|
||||
guard <| 4 ≤ e.getAppNumArgs
|
||||
guard <| e.isAppOf ``letFun
|
||||
@@ -2198,9 +2195,6 @@ private def natSubFn : Expr :=
|
||||
private def natMulFn : Expr :=
|
||||
mkApp4 (mkConst ``HMul.hMul [0, 0, 0]) Nat.mkType Nat.mkType Nat.mkType Nat.mkInstHMul
|
||||
|
||||
private def natPowFn : Expr :=
|
||||
mkApp4 (mkConst ``HPow.hPow [0, 0, 0]) Nat.mkType Nat.mkType Nat.mkType Nat.mkInstHPow
|
||||
|
||||
/-- Given `a : Nat`, returns `Nat.succ a` -/
|
||||
def mkNatSucc (a : Expr) : Expr :=
|
||||
mkApp (mkConst ``Nat.succ) a
|
||||
@@ -2217,10 +2211,6 @@ def mkNatSub (a b : Expr) : Expr :=
|
||||
def mkNatMul (a b : Expr) : Expr :=
|
||||
mkApp2 natMulFn a b
|
||||
|
||||
/-- Given `a b : Nat`, returns `a ^ b` -/
|
||||
def mkNatPow (a b : Expr) : Expr :=
|
||||
mkApp2 natPowFn a b
|
||||
|
||||
private def natLEPred : Expr :=
|
||||
mkApp2 (mkConst ``LE.le [0]) Nat.mkType Nat.mkInstLE
|
||||
|
||||
|
||||
@@ -484,7 +484,7 @@ where
|
||||
let startTime := (← IO.monoNanosNow).toFloat / 1000000000
|
||||
let mut opts := setup.opts
|
||||
-- HACK: no better way to enable in core with `USE_LAKE` off
|
||||
if setup.mainModuleName.getRoot ∈ [`Init, `Std, `Lean, `Lake] then
|
||||
if (`Init).isPrefixOf setup.mainModuleName then
|
||||
opts := experimental.module.setIfNotSet opts true
|
||||
if !stx.raw[0].isNone && !experimental.module.get opts then
|
||||
throw <| IO.Error.userError "`module` keyword is experimental and not enabled here"
|
||||
|
||||
@@ -522,7 +522,7 @@ partial def isSubPrefixOfAux (a₁ a₂ : PArray (Option LocalDecl)) (exceptFVar
|
||||
def isSubPrefixOf (lctx₁ lctx₂ : LocalContext) (exceptFVars : Array Expr := #[]) : Bool :=
|
||||
isSubPrefixOfAux lctx₁.decls lctx₂.decls exceptFVars 0 0
|
||||
|
||||
@[inline] def mkBinding (isLambda : Bool) (lctx : LocalContext) (xs : Array Expr) (b : Expr) (usedLetOnly : Bool := true) (generalizeNondepLet := false) : Expr :=
|
||||
@[inline] def mkBinding (isLambda : Bool) (lctx : LocalContext) (xs : Array Expr) (b : Expr) (generalizeNondepLet := false) : Expr :=
|
||||
let b := b.abstract xs
|
||||
xs.size.foldRev (init := b) fun i _ b =>
|
||||
let x := xs[i]
|
||||
@@ -538,7 +538,7 @@ def isSubPrefixOf (lctx₁ lctx₂ : LocalContext) (exceptFVars : Array Expr :=
|
||||
| some (.ldecl _ _ n ty val nondep _) =>
|
||||
if nondep && generalizeNondepLet then
|
||||
handleCDecl n ty .default
|
||||
else if !usedLetOnly || b.hasLooseBVar 0 then
|
||||
else if b.hasLooseBVar 0 then
|
||||
let ty := ty.abstractRange i xs
|
||||
let val := val.abstractRange i xs
|
||||
mkLet n ty val b nondep
|
||||
@@ -548,13 +548,13 @@ def isSubPrefixOf (lctx₁ lctx₂ : LocalContext) (exceptFVars : Array Expr :=
|
||||
|
||||
/-- Creates the expression `fun x₁ .. xₙ => b` for free variables `xs = #[x₁, .., xₙ]`,
|
||||
suitably abstracting `b` and the types for each of the `xᵢ`. -/
|
||||
def mkLambda (lctx : LocalContext) (xs : Array Expr) (b : Expr) (usedLetOnly : Bool := true) (generalizeNondepLet := false) : Expr :=
|
||||
mkBinding true lctx xs b usedLetOnly generalizeNondepLet
|
||||
def mkLambda (lctx : LocalContext) (xs : Array Expr) (b : Expr) (generalizeNondepLet := false) : Expr :=
|
||||
mkBinding true lctx xs b generalizeNondepLet
|
||||
|
||||
/-- Creates the expression `(x₁:α₁) → .. → (xₙ:αₙ) → b` for free variables `xs = #[x₁, .., xₙ]`,
|
||||
suitably abstracting `b` and the types for each of the `xᵢ`, `αᵢ`. -/
|
||||
def mkForall (lctx : LocalContext) (xs : Array Expr) (b : Expr) (usedLetOnly : Bool := true) (generalizeNondepLet := false) : Expr :=
|
||||
mkBinding false lctx xs b usedLetOnly generalizeNondepLet
|
||||
def mkForall (lctx : LocalContext) (xs : Array Expr) (b : Expr) (generalizeNondepLet := false) : Expr :=
|
||||
mkBinding false lctx xs b generalizeNondepLet
|
||||
|
||||
@[inline] def anyM [Monad m] (lctx : LocalContext) (p : LocalDecl → m Bool) : m Bool :=
|
||||
lctx.decls.anyM fun d => match d with
|
||||
|
||||
@@ -618,9 +618,7 @@ actually rendered. Consider using this function in lazy message data to avoid un
|
||||
computation for messages that are not displayed.
|
||||
-/
|
||||
private def MessageData.formatLength (ctx : PPContext) (msg : MessageData) : BaseIO Nat := do
|
||||
let { env, mctx, lctx, opts, currNamespace, openDecls } := ctx
|
||||
-- Simulate the naming context that will be added to the actual message
|
||||
let msg := MessageData.withNamingContext { currNamespace, openDecls } msg
|
||||
let { env, mctx, lctx, opts, ..} := ctx
|
||||
let fmt ← msg.format (some { env, mctx, lctx, opts })
|
||||
return fmt.pretty.length
|
||||
|
||||
|
||||
@@ -34,10 +34,9 @@ def mkExpectedTypeHint (e : Expr) (expectedType : Expr) : MetaM Expr := do
|
||||
return mkExpectedTypeHintCore e expectedType u
|
||||
|
||||
/--
|
||||
`mkLetFun x v e` creates `letFun v (fun x => e)`.
|
||||
`mkLetFun x v e` creates the encoding for the `let_fun x := v; e` expression.
|
||||
The expression `x` can either be a free variable or a metavariable, and the function suitably abstracts `x` in `e`.
|
||||
-/
|
||||
@[deprecated mkLetFVars (since := "2026-06-29")]
|
||||
def mkLetFun (x : Expr) (v : Expr) (e : Expr) : MetaM Expr := do
|
||||
-- If `x` is an `ldecl`, then the result of `mkLambdaFVars` is a let expression.
|
||||
let ensureLambda : Expr → Expr
|
||||
|
||||
@@ -1052,7 +1052,7 @@ Lift a `MkBindingM` monadic action `x` to `MetaM`.
|
||||
throwError "failed to create binder due to failure when reverting variable dependencies"
|
||||
|
||||
/--
|
||||
Similar to `abstractM` but consider only the first `min n xs.size` entries in `xs`
|
||||
Similar to `abstracM` but consider only the first `min n xs.size` entries in `xs`
|
||||
|
||||
It is also similar to `Expr.abstractRange`, but handles metavariables correctly.
|
||||
It uses `elimMVarDeps` to ensure `e` and the type of the free variables `xs` do not
|
||||
@@ -2545,38 +2545,6 @@ where
|
||||
|
||||
end Meta
|
||||
|
||||
open Meta
|
||||
|
||||
namespace PPContext
|
||||
|
||||
def runCoreM {α : Type} (ppCtx : PPContext) (x : CoreM α) : IO α :=
|
||||
Prod.fst <$> x.toIO { options := ppCtx.opts, currNamespace := ppCtx.currNamespace
|
||||
openDecls := ppCtx.openDecls
|
||||
fileName := "<PrettyPrinter>", fileMap := default
|
||||
diag := getDiag ppCtx.opts }
|
||||
{ env := ppCtx.env, ngen := { namePrefix := `_pp_uniq } }
|
||||
|
||||
def runMetaM {α : Type} (ppCtx : PPContext) (x : MetaM α) : IO α :=
|
||||
ppCtx.runCoreM <| x.run' { lctx := ppCtx.lctx } { mctx := ppCtx.mctx }
|
||||
|
||||
end PPContext
|
||||
|
||||
/--
|
||||
Turns a `MetaM MessageData` into a `MessageData.lazy` which will run the monadic value.
|
||||
The optional array of expressions is used to set the `hasSyntheticSorry` fields, and should
|
||||
comprise the expressions that are included in the message data.
|
||||
-/
|
||||
def MessageData.ofLazyM (f : MetaM MessageData) (es : Array Expr := #[]) : MessageData :=
|
||||
.lazy
|
||||
(f := fun ppctxt => do
|
||||
match (← ppctxt.runMetaM f |>.toBaseIO) with
|
||||
| .ok fmt => return fmt
|
||||
| .error ex => return m!"[Error pretty printing: {ex}]"
|
||||
)
|
||||
(hasSyntheticSorry := fun mvarctxt => es.any (fun a =>
|
||||
instantiateMVarsCore mvarctxt a |>.1.hasSyntheticSorry
|
||||
))
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `Meta.isLevelDefEq.postponed
|
||||
registerTraceClass `Meta.realizeConst
|
||||
|
||||
@@ -191,26 +191,18 @@ def throwLetTypeMismatchMessage {α} (fvarId : FVarId) : MetaM α := do
|
||||
| _ => unreachable!
|
||||
|
||||
/--
|
||||
Return error message "has type{givenType}\nbut is expected to have type{expectedType}"
|
||||
Adds the type’s types unless they are defeq.
|
||||
Return error message "has type{givenType}\nbut is expected to have type{expectedType}"
|
||||
-/
|
||||
def mkHasTypeButIsExpectedMsg (givenType expectedType : Expr) : MetaM MessageData :=
|
||||
return MessageData.ofLazyM (es := #[givenType, expectedType]) do
|
||||
try
|
||||
let givenTypeType ← inferType givenType
|
||||
let expectedTypeType ← inferType expectedType
|
||||
if (← isDefEqGuarded givenTypeType expectedTypeType) then
|
||||
let (givenType, expectedType) ← addPPExplicitToExposeDiff givenType expectedType
|
||||
return m!"has type{indentExpr givenType}\n\
|
||||
but is expected to have type{indentExpr expectedType}"
|
||||
else
|
||||
let (givenType, expectedType) ← addPPExplicitToExposeDiff givenType expectedType
|
||||
let (givenTypeType, expectedTypeType) ← addPPExplicitToExposeDiff givenTypeType expectedTypeType
|
||||
return m!"has type{indentExpr givenType}\nof sort{inlineExpr givenTypeType}\
|
||||
but is expected to have type{indentExpr expectedType}\nof sort{inlineExprTrailing expectedTypeType}"
|
||||
catch _ =>
|
||||
let (givenType, expectedType) ← addPPExplicitToExposeDiff givenType expectedType
|
||||
return m!"has type{indentExpr givenType}\nbut is expected to have type{indentExpr expectedType}"
|
||||
def mkHasTypeButIsExpectedMsg (givenType expectedType : Expr) : MetaM MessageData := do
|
||||
try
|
||||
let givenTypeType ← inferType givenType
|
||||
let expectedTypeType ← inferType expectedType
|
||||
let (givenType, expectedType) ← addPPExplicitToExposeDiff givenType expectedType
|
||||
let (givenTypeType, expectedTypeType) ← addPPExplicitToExposeDiff givenTypeType expectedTypeType
|
||||
return m!"has type{indentD m!"{givenType} : {givenTypeType}"}\nbut is expected to have type{indentD m!"{expectedType} : {expectedTypeType}"}"
|
||||
catch _ =>
|
||||
let (givenType, expectedType) ← addPPExplicitToExposeDiff givenType expectedType
|
||||
return m!"has type{indentExpr givenType}\nbut is expected to have type{indentExpr expectedType}"
|
||||
|
||||
def throwAppTypeMismatch (f a : Expr) : MetaM α := do
|
||||
let (expectedType, binfo) ← getFunctionDomain f
|
||||
|
||||
@@ -70,9 +70,6 @@ def decLevel (u : Level) : MetaM Level := do
|
||||
def getDecLevel (type : Expr) : MetaM Level := do
|
||||
decLevel (← getLevel type)
|
||||
|
||||
def getDecLevel? (type : Expr) : MetaM (Option Level) := do
|
||||
decLevel? (← getLevel type)
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `Meta.isLevelDefEq.step
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ import Lean.Meta.Basic
|
||||
import Lean.Meta.AppBuilder
|
||||
import Lean.Meta.Match.MatcherInfo
|
||||
import Lean.DefEqAttrib
|
||||
import Lean.Meta.LetToHave
|
||||
|
||||
namespace Lean.Meta
|
||||
|
||||
@@ -179,8 +178,6 @@ where doRealize name info := do
|
||||
lambdaTelescope (cleanupAnnotations := true) info.value fun xs body => do
|
||||
let lhs := mkAppN (mkConst info.name <| info.levelParams.map mkLevelParam) xs
|
||||
let type ← mkForallFVars xs (← mkEq lhs body)
|
||||
-- Note: if this definition was added using `def`, then `letToHave` has already been applied to the body.
|
||||
let type ← letToHave type
|
||||
let value ← mkLambdaFVars xs (← mkEqRefl lhs)
|
||||
addDecl <| Declaration.thmDecl {
|
||||
name, type, value
|
||||
|
||||
@@ -434,7 +434,7 @@ The `Meta.letToHave` trace class logs errors and messages.
|
||||
def letToHave (e : Expr) : MetaM Expr := do
|
||||
profileitM Exception "let-to-have transformation" (← getOptions) do
|
||||
let e ← instantiateMVars e
|
||||
withoutExporting <| LetToHave.main e
|
||||
LetToHave.main e
|
||||
|
||||
builtin_initialize
|
||||
registerTraceClass `Meta.letToHave
|
||||
|
||||
@@ -290,6 +290,14 @@ partial def foldAndCollect (oldIH newIH : FVarId) (isRecCall : Expr → Option E
|
||||
withTraceNode `Meta.FunInd (pure m!"{exceptEmoji ·} foldAndCollect ({mkFVar oldIH} → {mkFVar newIH})::{indentExpr e}") do
|
||||
|
||||
let e' ← id do
|
||||
if let some (n, t, v, b) := e.letFun? then
|
||||
let t' ← foldAndCollect oldIH newIH isRecCall t
|
||||
let v' ← foldAndCollect oldIH newIH isRecCall v
|
||||
return ← withLocalDeclD n t' fun x => do
|
||||
M.localMapM (mkLetFun x v' ·) do
|
||||
let b' ← foldAndCollect oldIH newIH isRecCall (b.instantiate1 x)
|
||||
mkLetFun x v' b'
|
||||
|
||||
if let some matcherApp ← matchMatcherApp? e (alsoCasesOn := true) then
|
||||
if matcherApp.remaining.size == 1 && matcherApp.remaining[0]!.isFVarOf oldIH then
|
||||
-- We do different things to the matcher when folding recursive calls and when
|
||||
@@ -665,6 +673,12 @@ def rwLetWith (h : Expr) (e : Expr) : MetaM Simp.Result := do
|
||||
def rwMData (e : Expr) : MetaM Simp.Result := do
|
||||
return { expr := e.consumeMData }
|
||||
|
||||
def rwHaveWith (h : Expr) (e : Expr) : MetaM Simp.Result := do
|
||||
if let some (_n, t, _v, b) := e.letFun? then
|
||||
if (← isDefEq t (← inferType h)) then
|
||||
return { expr := b.instantiate1 h }
|
||||
return { expr := e }
|
||||
|
||||
def rwFun (names : Array Name) (e : Expr) : MetaM Simp.Result := do
|
||||
e.withApp fun f xs => do
|
||||
if let some name := names.find? f.isConstOf then
|
||||
@@ -896,6 +910,14 @@ partial def buildInductionBody (toErase toClear : Array FVarId) (goal : Expr)
|
||||
buildInductionBody toErase toClear goal' oldIH newIH isRecCall (b.instantiate1 x)
|
||||
mkLetFVars #[x] b'
|
||||
|
||||
if let some (n, t, v, b) := e.letFun? then
|
||||
let t' ← foldAndCollect oldIH newIH isRecCall t
|
||||
let v' ← foldAndCollect oldIH newIH isRecCall v
|
||||
return ← withLetDecl n t' v' fun x => M2.branch do
|
||||
let b' ← withRewrittenMotiveArg goal (rwHaveWith x) fun goal' =>
|
||||
buildInductionBody toErase toClear goal' oldIH newIH isRecCall (b.instantiate1 x)
|
||||
mkLetFVars #[x] b' (usedLetOnly := false)
|
||||
|
||||
-- Special case for traversing the PProd’ed bodies in our encoding of structural mutual recursion
|
||||
if let .lam n t b bi := e then
|
||||
if goal.isForall then
|
||||
@@ -1035,7 +1057,6 @@ where doRealize (inductName : Name) := do
|
||||
|
||||
let eTyp ← inferType e'
|
||||
let eTyp ← elimTypeAnnotations eTyp
|
||||
let eTyp ← letToHave eTyp
|
||||
-- logInfo m!"eTyp: {eTyp}"
|
||||
let levelParams := (collectLevelParams {} eTyp).params
|
||||
-- Prune unused level parameters, preserving the original order
|
||||
@@ -1069,7 +1090,6 @@ def projectMutualInduct (unfolding : Bool) (names : Array Name) (mutualInduct :
|
||||
let value ← PProdN.projM names.size idx value
|
||||
mkLambdaFVars xs value
|
||||
let type ← inferType value
|
||||
let type ← letToHave type
|
||||
addDecl <| Declaration.thmDecl { name := inductName, levelParams, type, value }
|
||||
|
||||
if idx == 0 then finalizeFirstInd
|
||||
@@ -1228,7 +1248,6 @@ where doRealize inductName := do
|
||||
check value
|
||||
let type ← inferType value
|
||||
let type ← elimOptParam type
|
||||
let type ← letToHave type
|
||||
|
||||
addDecl <| Declaration.thmDecl
|
||||
{ name := inductName, levelParams := ci.levelParams, type, value }
|
||||
@@ -1461,7 +1480,6 @@ where doRealize inductName := do
|
||||
|
||||
let eTyp ← inferType e'
|
||||
let eTyp ← elimTypeAnnotations eTyp
|
||||
let eTyp ← letToHave eTyp
|
||||
-- logInfo m!"eTyp: {eTyp}"
|
||||
let levelParams := (collectLevelParams {} eTyp).params
|
||||
-- Prune unused level parameters, preserving the original order
|
||||
@@ -1528,6 +1546,9 @@ where
|
||||
modify (·.set! i true)
|
||||
for alt in args[matchInfo.getFirstAltPos...matchInfo.arity] do
|
||||
go xs alt
|
||||
if f.isConstOf ``letFun then
|
||||
for arg in args[3...4] do
|
||||
go xs arg
|
||||
if f.isConstOf ``ite || f.isConstOf ``dite then
|
||||
for arg in args[3...5] do
|
||||
go xs arg
|
||||
@@ -1602,7 +1623,6 @@ def deriveCases (unfolding : Bool) (name : Name) : MetaM Unit := do
|
||||
|
||||
let eTyp ← inferType e'
|
||||
let eTyp ← elimTypeAnnotations eTyp
|
||||
let eTyp ← letToHave eTyp
|
||||
-- logInfo m!"eTyp: {eTyp}"
|
||||
let levelParams := (collectLevelParams {} eTyp).params
|
||||
-- Prune unused level parameters, preserving the original order
|
||||
|
||||
@@ -12,4 +12,3 @@ import Lean.Meta.Tactic.Grind.Arith.Offset
|
||||
import Lean.Meta.Tactic.Grind.Arith.Cutsat
|
||||
import Lean.Meta.Tactic.Grind.Arith.CommRing
|
||||
import Lean.Meta.Tactic.Grind.Arith.Linear
|
||||
import Lean.Meta.Tactic.Grind.Arith.Simproc
|
||||
|
||||
@@ -9,7 +9,6 @@ import Lean.Meta.Tactic.Grind.Diseq
|
||||
import Lean.Meta.Tactic.Grind.Arith.ProofUtil
|
||||
import Lean.Meta.Tactic.Grind.Arith.CommRing.RingId
|
||||
import Lean.Meta.Tactic.Grind.Arith.CommRing.DenoteExpr
|
||||
import Lean.Meta.Tactic.Grind.Arith.CommRing.SafePoly
|
||||
import Lean.Meta.Tactic.Grind.Arith.CommRing.ToExpr
|
||||
|
||||
namespace Lean.Meta.Grind.Arith.CommRing
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.Meta.Tactic.Grind.Arith.CommRing.DenoteExpr
|
||||
|
||||
namespace Lean.Meta.Grind.Arith.CommRing
|
||||
|
||||
/-!
|
||||
The polynomial functions at `Poly.lean` are used for constructing proofs-by-reflection,
|
||||
but they do not provide mechanisms for aborting expensive computations.
|
||||
-/
|
||||
|
||||
private def applyChar (a : Int) : RingM Int := do
|
||||
if let some c ← nonzeroChar? then
|
||||
return a % c
|
||||
else
|
||||
return a
|
||||
|
||||
private def addConst (p : Poly) (k : Int) : RingM Poly := do
|
||||
if let some c ← nonzeroChar? then return .addConstC p k c else return .addConst p k
|
||||
|
||||
private def mulConst (k : Int) (p : Poly) : RingM Poly := do
|
||||
if let some c ← nonzeroChar? then return .mulConstC k p c else return .mulConst k p
|
||||
|
||||
private def mulMon (k : Int) (m : Mon) (p : Poly) : RingM Poly := do
|
||||
if let some c ← nonzeroChar? then return .mulMonC k m p c else return .mulMon k m p
|
||||
|
||||
private def combine (p₁ p₂ : Poly) : RingM Poly := withIncRecDepth do
|
||||
match p₁, p₂ with
|
||||
| .num k₁, .num k₂ => return .num (← applyChar (k₁ + k₂))
|
||||
| .num k₁, .add k₂ m₂ p₂ => addConst (.add k₂ m₂ p₂) k₁
|
||||
| .add k₁ m₁ p₁, .num k₂ => addConst (.add k₁ m₁ p₁) k₂
|
||||
| .add k₁ m₁ p₁, .add k₂ m₂ p₂ =>
|
||||
match m₁.grevlex m₂ with
|
||||
| .eq =>
|
||||
let k ← applyChar (k₁ + k₂)
|
||||
bif k == 0 then
|
||||
combine p₁ p₂
|
||||
else
|
||||
return .add k m₁ (← combine p₁ p₂)
|
||||
| .gt => return .add k₁ m₁ (← combine p₁ (.add k₂ m₂ p₂))
|
||||
| .lt => return .add k₂ m₂ (← combine (.add k₁ m₁ p₁) p₂)
|
||||
|
||||
private def mul (p₁ : Poly) (p₂ : Poly) : RingM Poly :=
|
||||
go p₁ (.num 0)
|
||||
where
|
||||
go (p₁ : Poly) (acc : Poly) : RingM Poly := withIncRecDepth do
|
||||
match p₁ with
|
||||
| .num k => combine acc (← mulConst k p₂)
|
||||
| .add k m p₁ =>
|
||||
checkSystem "grind ring"
|
||||
go p₁ (← combine acc (← mulMon k m p₂))
|
||||
|
||||
private def pow (p : Poly) (k : Nat) : RingM Poly := withIncRecDepth do
|
||||
match k with
|
||||
| 0 => return .num 1
|
||||
| 1 => return p
|
||||
| 2 => mul p p
|
||||
| k+3 => mul p (← pow p (k+2))
|
||||
|
||||
private def toPoly (e : RingExpr) : RingM Poly := do
|
||||
match e with
|
||||
| .num n => return .num (← applyChar n)
|
||||
| .var x => return .ofVar x
|
||||
| .add a b => combine (← toPoly a) (← toPoly b)
|
||||
| .mul a b => mul (← toPoly a) (← toPoly b)
|
||||
| .neg a => mulConst (-1) (← toPoly a)
|
||||
| .sub a b => combine (← toPoly a) (← mulConst (-1) (← toPoly b))
|
||||
| .pow a k =>
|
||||
if k == 0 then
|
||||
return .num 1
|
||||
else match a with
|
||||
| .num n => return .num (← applyChar (n^k))
|
||||
| .var x => return .ofMon (.mult {x, k} .unit)
|
||||
| _ => pow (← toPoly a) k
|
||||
|
||||
/--
|
||||
Converts the given ring expression into a multivariate polynomial.
|
||||
If the ring has a nonzero characteristic, it is used during normalization.
|
||||
-/
|
||||
abbrev _root_.Lean.Grind.CommRing.Expr.toPolyM (e : RingExpr) : RingM Poly := do
|
||||
toPoly e
|
||||
|
||||
abbrev _root_.Lean.Grind.CommRing.Poly.mulConstM (p : Poly) (k : Int) : RingM Poly :=
|
||||
mulConst k p
|
||||
|
||||
abbrev _root_.Lean.Grind.CommRing.Poly.mulMonM (p : Poly) (k : Int) (m : Mon) : RingM Poly :=
|
||||
mulMon k m p
|
||||
|
||||
abbrev _root_.Lean.Grind.CommRing.Poly.mulM (p₁ p₂ : Poly) : RingM Poly := do
|
||||
mul p₁ p₂
|
||||
|
||||
abbrev _root_.Lean.Grind.CommRing.Poly.combineM (p₁ p₂ : Poly) : RingM Poly :=
|
||||
combine p₁ p₂
|
||||
|
||||
def _root_.Lean.Grind.CommRing.Poly.spolM (p₁ p₂ : Poly) : RingM Grind.CommRing.SPolResult := do
|
||||
match p₁, p₂ with
|
||||
| .add k₁ m₁ p₁, .add k₂ m₂ p₂ =>
|
||||
let m := m₁.lcm m₂
|
||||
let m₁ := m.div m₁
|
||||
let m₂ := m.div m₂
|
||||
let g := Nat.gcd k₁.natAbs k₂.natAbs
|
||||
let c₁ := k₂/g
|
||||
let c₂ := -k₁/g
|
||||
let p₁ ← mulMon c₁ m₁ p₁
|
||||
let p₂ ← mulMon c₂ m₂ p₂
|
||||
let spol ← combine p₁ p₂
|
||||
return { spol, m₁, m₂, k₁ := c₁, k₂ := c₂ }
|
||||
| _, _ => return {}
|
||||
|
||||
end Lean.Meta.Grind.Arith.CommRing
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user