Compare commits

..

4 Commits

Author SHA1 Message Date
Kim Morrison
66400f8e77 oops 2025-06-29 21:24:30 +10:00
Kim Morrison
e5315e0521 namespaces 2025-06-29 21:15:45 +10:00
Kim Morrison
2472bdbaf2 help theorem for Std.ReflCmp 2025-06-29 21:01:52 +10:00
Kim Morrison
732f55ec38 feat: support for ReflCmp in grind 2025-06-29 15:59:28 +10:00
1458 changed files with 2567 additions and 5355 deletions

View File

@@ -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

View File

@@ -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
View File

@@ -31,4 +31,3 @@ fwOut.txt
wdErr.txt
wdIn.txt
wdOut.txt
downstream_releases/

View File

@@ -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")

View File

@@ -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

View File

@@ -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__":

View File

@@ -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

View File

@@ -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()

View File

@@ -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'")

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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} :

View File

@@ -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)]

View File

@@ -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.

View File

@@ -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 := #[] }

View File

@@ -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 ..

View File

@@ -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 := #[] }

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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 :=

View File

@@ -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

View File

@@ -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))

View File

@@ -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]

View File

@@ -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 (α := α) β} :

View File

@@ -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]

View File

@@ -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₂

View File

@@ -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)]

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)]

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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]

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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 whiteboard:** 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, Ematching,
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, graphcoloring reductions, highorder Nqueens boards,
@@ -227,28 +227,15 @@ For **bitlevel or combinatorial problems**, consider using **`bv_decide`**.
`bv_decide` calls a stateoftheart SAT solver (CaDiCaL) and then returns a
*compact, machinecheckable 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

View File

@@ -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])

View File

@@ -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

View File

@@ -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)

View File

@@ -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' _ _

View File

@@ -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

View File

@@ -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 β]

View File

@@ -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
/--

View File

@@ -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

View File

@@ -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; ?_)
/--

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 }

View File

@@ -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:
```

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 =>

View File

@@ -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

View File

@@ -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 α :=

View File

@@ -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

View File

@@ -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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 types 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 PProded 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

View File

@@ -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

View File

@@ -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

View File

@@ -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