Compare commits

..

8 Commits

Author SHA1 Message Date
Joachim Breitner
e2058f4666 Cache in env extension 2025-08-14 14:32:40 +02:00
Joachim Breitner
a9b64f3b79 More permissive 2025-08-13 23:02:38 +02:00
Joachim Breitner
1ba1309953 wrong branch 2025-08-13 22:36:42 +02:00
Joachim Breitner
2f9ce4d95c Update tests 2025-08-13 22:35:07 +02:00
Joachim Breitner
b55e6b7026 Move file 2025-08-13 22:32:18 +02:00
Joachim Breitner
ba78868b5e Update one test 2025-08-13 19:29:03 +02:00
Joachim Breitner
c80c099ca8 stash 2025-08-13 19:28:15 +02:00
Joachim Breitner
d0c5a43f21 stash 2025-08-13 18:44:03 +02:00
1277 changed files with 3053 additions and 6183 deletions

View File

@@ -18,14 +18,14 @@
# An old nixpkgs for creating releases with an old glibc
pkgsDist-old-aarch = import inputs.nixpkgs-old { localSystem.config = "aarch64-unknown-linux-gnu"; };
llvmPackages = pkgs.llvmPackages_15;
lean-packages = pkgs.callPackage (./nix/packages.nix) { src = ./.; };
devShellWithDist = pkgsDist: pkgs.mkShell.override {
stdenv = pkgs.overrideCC pkgs.stdenv llvmPackages.clang;
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
} ({
buildInputs = with pkgs; [
cmake gmp libuv ccache pkg-config
llvmPackages.llvm # llvm-symbolizer for asan/lsan
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
gdb
tree # for CI
];
@@ -60,6 +60,12 @@
GDB = pkgsDist.gdb;
});
in {
packages.${system} = {
# to be removed when Nix CI is not needed anymore
inherit (lean-packages) cacheRoots test update-stage0-commit ciShell;
deprecated = lean-packages;
};
devShells.${system} = {
# The default development shell for working on lean itself
default = devShellWithDist pkgs;

7
nix/bareStdenv/setup Normal file
View File

@@ -0,0 +1,7 @@
set -eo pipefail
for pkg in $buildInputs; do
export PATH=$PATH:$pkg/bin
done
: ${outputs:=out}

208
nix/bootstrap.nix Normal file
View File

@@ -0,0 +1,208 @@
{ src, debug ? false, stage0debug ? false, extraCMakeFlags ? [],
stdenv, lib, cmake, pkg-config, gmp, libuv, cadical, git, gnumake, bash, buildLeanPackage, writeShellScriptBin, runCommand, symlinkJoin, lndir, perl, gnused, darwin, llvmPackages, linkFarmFromDrvs,
... } @ args:
with builtins;
lib.warn "The Nix-based build is deprecated" rec {
inherit stdenv;
sourceByRegex = p: rs: lib.sourceByRegex p (map (r: "(/src/)?${r}") rs);
buildCMake = args: stdenv.mkDerivation ({
nativeBuildInputs = [ cmake pkg-config ];
buildInputs = [ gmp libuv llvmPackages.llvm ];
# https://github.com/NixOS/nixpkgs/issues/60919
hardeningDisable = [ "all" ];
dontStrip = (args.debug or debug);
postConfigure = ''
patchShebangs .
'';
} // args // {
src = args.realSrc or (sourceByRegex args.src [ "[a-z].*" "CMakeLists\.txt" ]);
cmakeFlags = ["-DSMALL_ALLOCATOR=ON" "-DUSE_MIMALLOC=OFF"] ++ (args.cmakeFlags or [ "-DSTAGE=1" "-DPREV_STAGE=./faux-prev-stage" "-DUSE_GITHASH=OFF" "-DCADICAL=${cadical}/bin/cadical" ]) ++ (args.extraCMakeFlags or extraCMakeFlags) ++ lib.optional (args.debug or debug) [ "-DCMAKE_BUILD_TYPE=Debug" ];
preConfigure = args.preConfigure or "" + ''
# ignore absence of submodule
sed -i 's!lake/Lake.lean!!' CMakeLists.txt
'';
});
lean-bin-tools-unwrapped = buildCMake {
name = "lean-bin-tools";
outputs = [ "out" "leanc_src" ];
realSrc = sourceByRegex (src + "/src") [ "CMakeLists\.txt" "[a-z].*" ".*\.in" "Leanc\.lean" ];
dontBuild = true;
installPhase = ''
mkdir $out $leanc_src
mv bin/ include/ share/ $out/
mv leanc.sh $out/bin/leanc
mv leanc/Leanc.lean $leanc_src/
substituteInPlace $out/bin/leanc --replace '$root' "$out" --replace " sed " " ${gnused}/bin/sed "
substituteInPlace $out/bin/leanmake --replace "make" "${gnumake}/bin/make"
substituteInPlace $out/share/lean/lean.mk --replace "/usr/bin/env bash" "${bash}/bin/bash"
'';
};
leancpp = buildCMake {
name = "leancpp";
src = src + "/src";
buildFlags = [ "leancpp" "leanrt" "leanrt_initial-exec" "leanshell" "leanmain" ];
installPhase = ''
mkdir -p $out
mv lib/ $out/
mv runtime/libleanrt_initial-exec.a $out/lib
'';
};
stage0 = args.stage0 or (buildCMake {
name = "lean-stage0";
realSrc = src + "/stage0/src";
debug = stage0debug;
cmakeFlags = [ "-DSTAGE=0" ];
extraCMakeFlags = [];
preConfigure = ''
ln -s ${src + "/stage0/stdlib"} ../stdlib
'';
installPhase = ''
mkdir -p $out/bin $out/lib/lean
mv bin/lean $out/bin/
mv lib/lean/*.{so,dylib} $out/lib/lean
'';
meta.mainProgram = "lean";
});
stage = { stage, prevStage, self }:
let
desc = "stage${toString stage}";
build = args: buildLeanPackage.override {
lean = prevStage;
leanc = lean-bin-tools-unwrapped;
# use same stage for retrieving dependencies
lean-leanDeps = stage0;
lean-final = self;
} ({
src = src + "/src";
roots = [ { mod = args.name; glob = "andSubmodules"; } ];
fullSrc = src;
srcPath = "$PWD/src:$PWD/src/lake";
inherit debug;
leanFlags = [ "-DwarningAsError=true" ];
} // args);
Init' = build { name = "Init"; deps = []; };
Std' = build { name = "Std"; deps = [ Init' ]; };
Lean' = build { name = "Lean"; deps = [ Std' ]; };
attachSharedLib = sharedLib: pkg: pkg // {
inherit sharedLib;
mods = mapAttrs (_: m: m // { inherit sharedLib; propagatedLoadDynlibs = []; }) pkg.mods;
};
in (all: all // all.lean) rec {
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
Init = attachSharedLib leanshared Init';
Std = attachSharedLib leanshared Std' // { allExternalDeps = [ Init ]; };
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Std ]; };
Lake = build {
name = "Lake";
sharedLibName = "Lake_shared";
src = src + "/src/lake";
deps = [ Init Lean ];
};
Lake-Main = build {
name = "LakeMain";
roots = [{ glob = "one"; mod = "LakeMain"; }];
executableName = "lake";
deps = [ Lake ];
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
src = src + "/src/lake";
};
stdlib = [ Init Std Lean Lake ];
modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); };
depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; };
iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; };
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
stdlibLinkFlags = "${lib.concatMapStringsSep " " (l: "-L${l.staticLib}") stdlib} -L${leancpp}/lib/lean";
libInit_shared = runCommand "libInit_shared" { buildInputs = [ stdenv.cc ]; libName = "libInit_shared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
mkdir $out
touch empty.c
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
'';
leanshared_1 = runCommand "leanshared_1" { buildInputs = [ stdenv.cc ]; libName = "leanshared_1${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
mkdir $out
touch empty.c
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
'';
leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
mkdir $out
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Wl,-Bsymbolic"} \
-Wl,--whole-archive ${leancpp}/lib/temp/libleanshell.a -lInit -lStd -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++ \
-lm ${stdlibLinkFlags} \
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
-o $out/$libName
'';
mods = foldl' (mods: pkg: mods // pkg.mods) {} stdlib;
print-paths = Lean.makePrintPathsFor [] mods;
leanc = writeShellScriptBin "leanc" ''
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${libInit_shared} -L${leanshared_1} -L${leanshared} -L${Lake.sharedLib} "$@"
'';
lean = runCommand "lean" { buildInputs = lib.optional stdenv.isDarwin darwin.cctools; } ''
mkdir -p $out/bin
${leanc}/bin/leanc ${leancpp}/lib/temp/libleanmain.a ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* -o $out/bin/lean
'';
# derivation following the directory layout of the "basic" setup, mostly useful for running tests
lean-all = stdenv.mkDerivation {
name = "lean-${desc}";
buildCommand = ''
mkdir -p $out/bin $out/lib/lean
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${libInit_shared}/* ${leanshared_1}/* ${leanshared}/* ${Lake.sharedLib}/* $out/lib/lean/
# put everything in a single final derivation so `IO.appDir` references work
cp ${lean}/bin/lean ${leanc}/bin/leanc ${Lake-Main.executable}/bin/lake $out/bin
# NOTE: `lndir` will not override existing `bin/leanc`
${lndir}/bin/lndir -silent ${lean-bin-tools-unwrapped} $out
'';
meta.mainProgram = "lean";
};
cacheRoots = linkFarmFromDrvs "cacheRoots" ([
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
] ++ map (lib: lib.oTree) stdlib);
test = buildCMake {
name = "lean-test-${desc}";
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
buildInputs = [ gmp libuv perl git cadical ];
preConfigure = ''
cd src
'';
extraCMakeFlags = [ "-DLLVM=OFF" ];
postConfigure = ''
patchShebangs ../../tests ../lake
rm -r bin lib include share
ln -sf ${lean-all}/* .
'';
buildPhase = ''
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)|leanlaketest_reverse-ffi|leanruntest_timeIO' -j$NIX_BUILD_CORES
'';
installPhase = ''
mkdir $out
mv test-results.xml $out
'';
};
update-stage0 =
let cTree = symlinkJoin { name = "cs"; paths = map (lib: lib.cTree) (stdlib ++ [Lake-Main]); }; in
writeShellScriptBin "update-stage0" ''
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/lib/update-stage0"}
'';
update-stage0-commit = writeShellScriptBin "update-stage0-commit" ''
set -euo pipefail
${update-stage0}/bin/update-stage0
git commit -m "chore: update stage0"
'';
link-ilean = writeShellScriptBin "link-ilean" ''
dest=''${1:-src}
rm -rf $dest/build/lib || true
mkdir -p $dest/build/lib
ln -s ${iTree}/* $dest/build/lib
'';
benchmarks =
let
entries = attrNames (readDir (src + "/tests/bench"));
leanFiles = map (n: elemAt n 0) (filter (n: n != null) (map (match "(.*)\.lean") entries));
in lib.genAttrs leanFiles (n: (buildLeanPackage {
name = n;
src = filterSource (e: _: baseNameOf e == "${n}.lean") (src + "/tests/bench");
}).executable);
};
stage1 = stage { stage = 1; prevStage = stage0; self = stage1; };
stage2 = stage { stage = 2; prevStage = stage1; self = stage2; };
stage3 = stage { stage = 3; prevStage = stage2; self = stage3; };
}

247
nix/buildLeanPackage.nix Normal file
View File

@@ -0,0 +1,247 @@
{ lean, lean-leanDeps ? lean, lean-final ? lean, leanc,
stdenv, lib, coreutils, gnused, writeShellScriptBin, bash, substituteAll, symlinkJoin, linkFarmFromDrvs,
runCommand, darwin, mkShell, ... }:
let lean-final' = lean-final; in
lib.makeOverridable (
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
# Lean dependencies. Each entry should be an output of buildLeanPackage.
deps ? [ lean.Init lean.Std lean.Lean ],
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
staticLibDeps ? [],
# Whether to wrap static library inputs in a -Wl,--start-group [...] -Wl,--end-group to ensure dependencies are resolved.
groupStaticLibs ? false,
# Shared library dependencies included at interpretation with --load-dynlib and linked to. Each derivation `shared` should contain a
# shared library at the path `${shared}/${shared.libName or shared.name}` and a name to link to like `-l${shared.linkName or shared.name}`.
# These libs are also linked to in packages that depend on this one.
nativeSharedLibs ? [],
# Lean modules to include.
# A set of Lean modules names as strings (`"Foo.Bar"`) or attrsets (`{ name = "Foo.Bar"; glob = "one" | "submodules" | "andSubmodules"; }`);
# see Lake README for glob meanings. Dependencies of selected modules are always included.
roots ? [ name ],
# Output from `lean --deps-json` on package source files. Persist the corresponding output attribute to a file and pass it back in here to avoid IFD.
# Must be refreshed on any change in `import`s or set of source file names.
modDepsFile ? null,
# Whether to compile each module into a native shared library that is loaded whenever the module is imported in order to accelerate evaluation
precompileModules ? false,
# Whether to compile the package into a native shared library that is loaded whenever *any* of the package's modules is imported into another package.
# If `precompileModules` is also `true`, the latter only affects imports within the current package.
precompilePackage ? precompileModules,
# Lean plugin dependencies. Each derivation `plugin` should contain a plugin library at path `${plugin}/${plugin.name}`.
pluginDeps ? [],
# `overrideAttrs` for `buildMod`
overrideBuildModAttrs ? null,
debug ? false, leanFlags ? [], leancFlags ? [], linkFlags ? [], executableName ? lib.toLower name, libName ? name, sharedLibName ? libName,
srcTarget ? "..#stage0", srcArgs ? "(\${args[*]})", lean-final ? lean-final' }@args:
with builtins; let
# "Init.Core" ~> "Init/Core"
modToPath = mod: replaceStrings ["."] ["/"] mod;
modToAbsPath = mod: "${src}/${modToPath mod}";
# sanitize file name before copying to store, except when already in store
copyToStoreSafe = base: suffix: if lib.isDerivation base then base + suffix else
builtins.path { name = lib.strings.sanitizeDerivationName (baseNameOf suffix); path = base + suffix; };
modToLean = mod: copyToStoreSafe src "/${modToPath mod}.lean";
bareStdenv = ./bareStdenv;
mkBareDerivation = args: derivation (args // {
name = lib.strings.sanitizeDerivationName args.name;
stdenv = bareStdenv;
inherit (stdenv) system;
buildInputs = (args.buildInputs or []) ++ [ coreutils ];
builder = stdenv.shell;
args = [ "-c" ''
source $stdenv/setup
set -u
${args.buildCommand}
'' ];
}) // { overrideAttrs = f: mkBareDerivation (lib.fix (lib.extends f (_: args))); };
runBareCommand = name: args: buildCommand: mkBareDerivation (args // { inherit name buildCommand; });
runBareCommandLocal = name: args: buildCommand: runBareCommand name (args // {
preferLocalBuild = true;
allowSubstitutes = false;
}) buildCommand;
mkSharedLib = name: args: runBareCommand "${name}-dynlib" {
buildInputs = [ stdenv.cc ] ++ lib.optional stdenv.isDarwin darwin.cctools;
libName = "${name}${stdenv.hostPlatform.extensions.sharedLibrary}";
} ''
mkdir -p $out
${leanc}/bin/leanc -shared ${args} -o $out/$libName
'';
depRoot = name: deps: mkBareDerivation {
name = "${name}-depRoot";
inherit deps;
depRoots = map (drv: drv.LEAN_PATH) deps;
passAsFile = [ "deps" "depRoots" ];
buildCommand = ''
mkdir -p $out
for i in $(cat $depRootsPath); do
cp -dru --no-preserve=mode $i/. $out
done
for i in $(cat $depsPath); do
cp -drsu --no-preserve=mode $i/. $out
done
'';
};
srcRoot = src;
# A flattened list of Lean-module dependencies (`deps`)
allExternalDeps = lib.unique (lib.foldr (dep: allExternalDeps: allExternalDeps ++ [ dep ] ++ dep.allExternalDeps) [] deps);
allNativeSharedLibs =
lib.unique (lib.flatten (nativeSharedLibs ++ (map (dep: dep.allNativeSharedLibs or []) allExternalDeps)));
# A flattened list of all static library dependencies: this and every dep module's explicitly provided `staticLibDeps`,
# plus every dep module itself: `dep.staticLib`
allStaticLibDeps =
lib.unique (lib.flatten (staticLibDeps ++ (map (dep: [dep.staticLib] ++ dep.staticLibDeps or []) allExternalDeps)));
pathOfSharedLib = dep: dep.libPath or "${dep}/${dep.libName or dep.name}";
leanPluginFlags = lib.concatStringsSep " " (map (dep: "--plugin=${pathOfSharedLib dep}") pluginDeps);
loadDynlibsOfDeps = deps: lib.unique (concatMap (d: d.propagatedLoadDynlibs) deps);
# submodules "Init" = ["Init.List.Basic", "Init.Core", ...]
submodules = mod: let
dir = readDir (modToAbsPath mod);
f = p: t:
if t == "directory" then
submodules "${mod}.${p}"
else
let m = builtins.match "(.*)\.lean" p;
in lib.optional (m != null) "${mod}.${head m}";
in concatLists (lib.mapAttrsToList f dir);
# conservatively approximate list of source files matched by glob
expandGlobAllApprox = g:
if typeOf g == "string" then
# we can't know the required files without parsing dependencies (which is what we want this
# function for), so we approximate to the entire package.
let root = (head (split "\\." g));
in lib.optional (pathExists (src + "/${modToPath root}.lean")) root ++ lib.optionals (pathExists (modToAbsPath root)) (submodules root)
else if g.glob == "one" then expandGlobAllApprox g.mod
else if g.glob == "submodules" then submodules g.mod
else if g.glob == "andSubmodules" then [g.mod] ++ submodules g.mod
else throw "unknown glob kind '${g}'";
# list of modules that could potentially be involved in the build
candidateMods = lib.unique (concatMap expandGlobAllApprox roots);
candidateFiles = map modToLean candidateMods;
modDepsFile = args.modDepsFile or mkBareDerivation {
name = "${name}-deps.json";
candidateFiles = lib.concatStringsSep " " candidateFiles;
passAsFile = [ "candidateFiles" ];
buildCommand = ''
mkdir $out
${lean-leanDeps}/bin/lean --deps-json --stdin < $candidateFilesPath > $out/$name
'';
};
modDeps = fromJSON (
# the only possible references to store paths in the JSON should be inside errors, so no chance of missed dependencies from this
unsafeDiscardStringContext (readFile "${modDepsFile}/${modDepsFile.name}"));
# map from module name to list of imports
modDepsMap = listToAttrs (lib.zipListsWith lib.nameValuePair candidateMods modDeps.imports);
maybeOverrideAttrs = f: x: if f != null then x.overrideAttrs f else x;
# build module (.olean and .c) given derivations of all (immediate) dependencies
# TODO: make `rec` parts override-compatible?
buildMod = mod: deps: maybeOverrideAttrs overrideBuildModAttrs (mkBareDerivation rec {
name = "${mod}";
LEAN_PATH = depRoot mod deps;
LEAN_ABORT_ON_PANIC = "1";
relpath = modToPath mod;
buildInputs = [ lean ];
leanPath = relpath + ".lean";
# should be either single .lean file or directory directly containing .lean file plus dependencies
src = copyToStoreSafe srcRoot ("/" + leanPath);
outputs = [ "out" "ilean" "c" ];
oleanPath = relpath + ".olean";
ileanPath = relpath + ".ilean";
cPath = relpath + ".c";
inherit leanFlags leanPluginFlags;
leanLoadDynlibFlags = map (p: "--load-dynlib=${pathOfSharedLib p}") (loadDynlibsOfDeps deps);
buildCommand = ''
dir=$(dirname $relpath)
mkdir -p $dir $out/$dir $ilean/$dir $c/$dir
if [ -d $src ]; then cp -r $src/. .; else cp $src $leanPath; fi
lean -o $out/$oleanPath -i $out/$ileanPath -c $c/$cPath $leanPath $leanFlags $leanPluginFlags $leanLoadDynlibFlags
'';
}) // {
inherit deps;
propagatedLoadDynlibs = loadDynlibsOfDeps deps;
};
compileMod = mod: drv: mkBareDerivation {
name = "${mod}-cc";
buildInputs = [ leanc stdenv.cc ];
hardeningDisable = [ "all" ];
oPath = drv.relpath + ".o";
inherit leancFlags;
buildCommand = ''
mkdir -p $out/$(dirname ${drv.relpath})
# make local "copy" so `drv`'s Nix store path doesn't end up in ccache's hash
ln -s ${drv.c}/${drv.cPath} src.c
# on the other hand, a debug build is pretty fast anyway, so preserve the path for gdb
leanc -c -o $out/$oPath $leancFlags -fPIC ${if debug then "${drv.c}/${drv.cPath} -g" else "src.c -O3 -DNDEBUG -DLEAN_EXPORTING"}
'';
};
mkMod = mod: deps:
let drv = buildMod mod deps;
obj = compileMod mod drv;
# this attribute will only be used if any dependent module is precompiled
sharedLib = mkSharedLib mod "${obj}/${obj.oPath} ${lib.concatStringsSep " " (map (d: pathOfSharedLib d.sharedLib) deps)}";
in drv // {
inherit obj sharedLib;
} // lib.optionalAttrs precompileModules {
propagatedLoadDynlibs = [sharedLib];
};
externalModMap = lib.foldr (dep: depMap: depMap // dep.mods) {} allExternalDeps;
# map from module name to derivation
modCandidates = mapAttrs (mod: header:
let
deps = if header.errors == []
then map (m: m.module) header.result.imports
else abort "errors while parsing imports of ${mod}:\n${lib.concatStringsSep "\n" header.errors}";
in mkMod mod (map (dep: if modDepsMap ? ${dep} then modCandidates.${dep} else externalModMap.${dep}) deps)) modDepsMap;
expandGlob = g:
if typeOf g == "string" then [g]
else if g.glob == "one" then [g.mod]
else if g.glob == "submodules" then submodules g.mod
else if g.glob == "andSubmodules" then [g.mod] ++ submodules g.mod
else throw "unknown glob kind '${g}'";
# subset of `modCandidates` that is transitively reachable from `roots`
mods' = listToAttrs (map (e: { name = e.key; value = modCandidates.${e.key}; }) (genericClosure {
startSet = map (m: { key = m; }) (concatMap expandGlob roots);
operator = e: if modDepsMap ? ${e.key} then map (m: { key = m.module; }) (filter (m: modCandidates ? ${m.module}) modDepsMap.${e.key}.result.imports) else [];
}));
allLinkFlags = lib.foldr (shared: acc: acc ++ [ "-L${shared}" "-l${shared.linkName or shared.name}" ]) linkFlags allNativeSharedLibs;
objects = mapAttrs (_: m: m.obj) mods';
bintools = if stdenv.isDarwin then darwin.cctools else stdenv.cc.bintools.bintools;
staticLib = runCommand "${name}-lib" { buildInputs = [ bintools ]; } ''
mkdir -p $out
ar Trcs $out/lib${libName}.a ${lib.concatStringsSep " " (map (drv: "${drv}/${drv.oPath}") (attrValues objects))};
'';
staticLibLinkWrapper = libs: if groupStaticLibs && !stdenv.isDarwin
then "-Wl,--start-group ${libs} -Wl,--end-group"
else "${libs}";
in rec {
inherit name lean deps staticLibDeps allNativeSharedLibs allLinkFlags allExternalDeps src objects staticLib modDepsFile;
mods = mapAttrs (_: m:
m //
# if neither precompilation option was set but a dependent module wants to be precompiled, default to precompiling this package whole
lib.optionalAttrs (precompilePackage || !precompileModules) { inherit sharedLib; } //
lib.optionalAttrs precompilePackage { propagatedLoadDynlibs = [sharedLib]; })
mods';
modRoot = depRoot name (attrValues mods);
depRoots = linkFarmFromDrvs "depRoots" (map (m: m.LEAN_PATH) (attrValues mods));
cTree = symlinkJoin { name = "${name}-cTree"; paths = map (mod: mod.c) (attrValues mods); };
oTree = symlinkJoin { name = "${name}-oTree"; paths = (attrValues objects); };
iTree = symlinkJoin { name = "${name}-iTree"; paths = map (mod: mod.ilean) (attrValues mods); };
sharedLib = mkSharedLib "lib${sharedLibName}" ''
${if stdenv.isDarwin then "-Wl,-force_load,${staticLib}/lib${libName}.a" else "-Wl,--whole-archive ${staticLib}/lib${libName}.a -Wl,--no-whole-archive"} \
${lib.concatStringsSep " " (map (d: "${d.sharedLib}/*") deps)}'';
executable = lib.makeOverridable ({ withSharedStdlib ? true }: let
objPaths = map (drv: "${drv}/${drv.oPath}") (attrValues objects) ++ lib.optional withSharedStdlib "${lean-final.leanshared}/*";
in runCommand executableName { buildInputs = [ stdenv.cc leanc ]; } ''
mkdir -p $out/bin
leanc ${staticLibLinkWrapper (lib.concatStringsSep " " (objPaths ++ map (d: "${d}/*.a") allStaticLibDeps))} \
-o $out/bin/${executableName} \
${lib.concatStringsSep " " allLinkFlags}
'') {};
})

42
nix/lake-dev.in Normal file
View File

@@ -0,0 +1,42 @@
#!@bash@/bin/bash
set -euo pipefail
function pebkac() {
echo 'This is just a simple Nix adapter for `lake print-paths|serve`.'
exit 1
}
[[ $# -gt 0 ]] || pebkac
case $1 in
--version)
# minimum version for `lake serve` with fallback
echo 3.1.0
;;
print-paths)
shift
deps="$@"
root=.
# fall back to initial package if not in package
[[ ! -f "$root/flake.nix" ]] && root="@srcRoot@"
target="$root#print-paths"
args=()
# HACK: use stage 0 instead of 1 inside Lean's own `src/`
[[ -d Lean && -f ../flake.nix ]] && target="@srcTarget@print-paths" && args=@srcArgs@
for dep in $deps; do
target="$target.\"$dep\""
done
echo "Building dependencies..." >&2
# -v only has "built ...", but "-vv" is a bit too verbose
exec @nix@/bin/nix run "$target" ${args[*]} -v
;;
serve)
shift
[[ ${1:-} == "--" ]] && shift
# `link-ilean` puts them there
LEAN_PATH=${LEAN_PATH:+$LEAN_PATH:}$PWD/build/lib exec $(dirname $0)/lean --server "$@"
;;
*)
pebkac
;;
esac

28
nix/lean-dev.in Normal file
View File

@@ -0,0 +1,28 @@
#!@bash@/bin/bash
set -euo pipefail
root="."
# find package root
while [[ "$root" != / ]]; do
[ -f "$root/flake.nix" ] && break
root="$(realpath "$root/..")"
done
# fall back to initial package if not in package
[[ ! -f "$root/flake.nix" ]] && root="@srcRoot@"
# use Lean w/ package unless in server mode (which has its own LEAN_PATH logic)
target="$root#lean-package"
for arg in "$@"; do
case $arg in
--server | --worker | -v | --version)
target="$root#lean"
;;
esac
done
args=(-- "$@")
# HACK: use stage 0 instead of 1 inside Lean's own `src/`
[[ -d Lean && -f ../flake.nix ]] && target="@srcTarget@" && args=@srcArgs@
LEAN_SYSROOT="$(dirname "$0")/.." exec @nix@/bin/nix ${LEAN_NIX_ARGS:-} run "$target" ${args[*]}

52
nix/packages.nix Normal file
View File

@@ -0,0 +1,52 @@
{ src, pkgs, ... } @ args:
with pkgs;
let
# https://github.com/NixOS/nixpkgs/issues/130963
llvmPackages = if stdenv.isDarwin then llvmPackages_11 else llvmPackages_15;
cc = (ccacheWrapper.override rec {
cc = llvmPackages.clang;
extraConfig = ''
export CCACHE_DIR=/nix/var/cache/ccache
export CCACHE_UMASK=007
export CCACHE_BASE_DIR=$NIX_BUILD_TOP
# https://github.com/NixOS/nixpkgs/issues/109033
args=("$@")
for ((i=0; i<"''${#args[@]}"; i++)); do
case ''${args[i]} in
-frandom-seed=*) unset args[i]; break;;
esac
done
set -- "''${args[@]}"
[ -d $CCACHE_DIR ] || exec ${cc}/bin/$(basename "$0") "$@"
'';
}).overrideAttrs (old: {
# https://github.com/NixOS/nixpkgs/issues/119779
installPhase = builtins.replaceStrings ["use_response_file_by_default=1"] ["use_response_file_by_default=0"] old.installPhase;
});
stdenv' = if stdenv.isLinux then useGoldLinker stdenv else stdenv;
lean = callPackage (import ./bootstrap.nix) (args // {
stdenv = overrideCC stdenv' cc;
inherit src buildLeanPackage llvmPackages;
});
makeOverridableLeanPackage = f:
let newF = origArgs: f origArgs // {
overrideArgs = newArgs: makeOverridableLeanPackage f (origArgs // newArgs);
};
in lib.setFunctionArgs newF (lib.getFunctionArgs f) // {
override = args: makeOverridableLeanPackage (f.override args);
};
buildLeanPackage = makeOverridableLeanPackage (callPackage (import ./buildLeanPackage.nix) (args // {
inherit (lean) stdenv;
lean = lean.stage1;
inherit (lean.stage1) leanc;
}));
in {
inherit cc buildLeanPackage llvmPackages;
nixpkgs = pkgs;
ciShell = writeShellScriptBin "ciShell" ''
set -o pipefail
export PATH=${moreutils}/bin:$PATH
# prefix lines with cumulative and individual execution time
"$@" |& ts -i "(%.S)]" | ts -s "[%M:%S"
'';
} // lean.stage1

View File

@@ -0,0 +1 @@
#eval "Hello, world!"

View File

@@ -0,0 +1,21 @@
{
description = "My Lean package";
inputs.lean.url = "github:leanprover/lean4";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = { self, lean, flake-utils }: flake-utils.lib.eachDefaultSystem (system:
let
leanPkgs = lean.packages.${system};
pkg = leanPkgs.buildLeanPackage {
name = "MyPackage"; # must match the name of the top-level .lean file
src = ./.;
};
in {
packages = pkg // {
inherit (leanPkgs) lean;
};
defaultPackage = pkg.modRoot;
});
}

View File

@@ -10,7 +10,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 24)
set(LEAN_VERSION_MINOR 23)
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

@@ -29,29 +29,6 @@ theorem id_def {α : Sort u} (a : α) : id a = a := rfl
attribute [grind] id
/--
A helper gadget for instructing the kernel to eagerly reduce terms.
When the gadget wraps the argument of an application, then when checking that
the expected and inferred type of the argument match, the kernel will evaluate terms more eagerly.
It is often used to wrap `Eq.refl true` proof terms as `eagerReduce (Eq.refl true)`
when using proof by reflection.
As an example, consider the theorem:
```
theorem eq_norm (ctx : Context) (p₁ p₂ : Poly) (h : (p₁.norm == p₂) = true) :
p₁.denote ctx = 0 → p₂.denote ctx = 0
```
The argument `h : (p₁.norm == p₂) = true` is a candidate for `eagerReduce`.
When applying this theorem, we would write:
```
eq_norm ctx p q (eagerReduce (Eq.refl true)) h
```
to instruct the kernel to use eager reduction when establishing that `(p.norm == q) = true` is
definitionally equal to `true = true`.
-/
@[expose] def eagerReduce {α : Sort u} (a : α) : α := a
/--
`flip f a b` is `f b a`. It is useful for "point-free" programming,
since it can sometimes be used to avoid introducing variables.

View File

@@ -49,6 +49,5 @@ public import Init.Data.Vector
public import Init.Data.Iterators
public import Init.Data.Range.Polymorphic
public import Init.Data.Slice
public import Init.Data.Order
public section

View File

@@ -12,12 +12,9 @@ public import Init.Data.Array.Lemmas
public import Init.Data.List.Lex
import Init.Data.Range.Polymorphic.Lemmas
import Init.Data.Range.Polymorphic.NatLemmas
import Init.Data.Order.Lemmas
public section
open Std
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
@@ -31,8 +28,8 @@ namespace Array
@[simp] theorem lt_toList [LT α] {xs ys : Array α} : xs.toList < ys.toList xs < ys := Iff.rfl
@[simp] theorem le_toList [LT α] {xs ys : Array α} : xs.toList ys.toList xs ys := Iff.rfl
grind_pattern _root_.List.lt_toArray => l₁.toArray < l₂.toArray
grind_pattern _root_.List.le_toArray => l₁.toArray l₂.toArray
grind_pattern _root_.List.lt_toArray => l₁.toArray < l₂.toArray
grind_pattern _root_.List.le_toArray => l₁.toArray l₂.toArray
grind_pattern lt_toList => xs.toList < ys.toList
grind_pattern le_toList => xs.toList ys.toList
@@ -103,14 +100,6 @@ theorem singleton_lex_singleton [BEq α] {lt : αα → Bool} : #[a].lex #[
xs.toList.lex ys.toList lt = xs.lex ys lt := by
cases xs <;> cases ys <;> simp
instance [LT α] [LE α] [LawfulOrderLT α] [IsLinearOrder α] : IsLinearOrder (Array α) := by
apply IsLinearOrder.of_le
· constructor
intro _ _ hab hba
simpa using Std.le_antisymm (α := List α) hab hba
· constructor; exact Std.le_trans (α := List α)
· constructor; exact fun _ _ => Std.le_total (α := List α)
protected theorem lt_irrefl [LT α] [Std.Irrefl (· < · : α α Prop)] (xs : Array α) : ¬ xs < xs :=
List.lt_irrefl xs.toList
@@ -142,35 +131,27 @@ instance [LT α] [Trans (· < · : αα → Prop) (· < ·) (· < ·)] :
Trans (· < · : Array α Array α Prop) (· < ·) (· < ·) where
trans h₁ h₂ := Array.lt_trans h₁ h₂
protected theorem lt_of_le_of_lt [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
Std.lt_of_le_of_lt (α := List α) h₁ h₂
@[deprecated Array.lt_of_le_of_lt (since := "2025-08-01")]
protected theorem lt_of_le_of_lt' [LT α]
protected theorem lt_of_le_of_lt [LT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
letI := LE.ofLT α
haveI : IsLinearOrder α := IsLinearOrder.of_lt
Array.lt_of_le_of_lt h₁ h₂
List.lt_of_le_of_lt h₁ h₂
protected theorem le_trans [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α]
protected theorem le_trans [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
fun h₃ => h₁ (Array.lt_of_le_of_lt h₂ h₃)
@[deprecated Array.le_trans (since := "2025-08-01")]
protected theorem le_trans' [LT α]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Array α} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
letI := LE.ofLT α
haveI : IsLinearOrder α := IsLinearOrder.of_lt
Array.le_trans h₁ h₂
instance [LE α] [LT α] [LawfulOrderLT α] [IsLinearOrder α] :
instance [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)] :
Trans (· · : Array α Array α Prop) (· ·) (· ·) where
trans h₁ h₂ := Array.le_trans h₁ h₂
@@ -184,7 +165,7 @@ instance [LT α]
asymm _ _ := Array.lt_asymm
protected theorem le_total [LT α]
[i : Std.Asymm (· < · : α α Prop)] (xs ys : Array α) : xs ys ys xs :=
[i : Std.Total (¬ · < · : α α Prop)] (xs ys : Array α) : xs ys ys xs :=
List.le_total xs.toList ys.toList
@[simp] protected theorem not_lt [LT α]
@@ -194,22 +175,19 @@ protected theorem le_total [LT α]
{xs ys : Array α} : ¬ ys xs xs < ys := Classical.not_not
protected theorem le_of_lt [LT α]
[i : Std.Asymm (· < · : α α Prop)]
[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 α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Asymm (· < · : α α 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)
protected theorem le_antisymm [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
{xs ys : Array α} : xs ys ys xs xs = ys := by
simpa using List.le_antisymm (as := xs.toList) (bs := ys.toList)
instance [LT α] [Std.Asymm (· < · : α α Prop)] :
instance [LT α]
[Std.Total (¬ · < · : α α Prop)] :
Std.Total (· · : Array α Array α Prop) where
total := Array.le_total
@@ -288,6 +266,7 @@ protected theorem lt_iff_exists [LT α] {xs ys : Array α} :
simp [List.lt_iff_exists]
protected theorem le_iff_exists [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)] {xs ys : Array α} :
xs ys
@@ -307,6 +286,7 @@ theorem append_left_lt [LT α] {xs ys zs : Array α} (h : ys < zs) :
simpa using List.append_left_lt h
theorem append_left_le [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
{xs ys zs : Array α} (h : ys zs) :
@@ -330,8 +310,10 @@ protected theorem map_lt [LT α] [LT β]
simpa using List.map_lt w h
protected theorem map_le [LT α] [LT β]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Irrefl (· < · : β β Prop)]
[Std.Asymm (· < · : β β Prop)]
[Std.Antisymm (¬ · < · : β β Prop)]
{xs ys : Array α} {f : α β} (w : x y, x < y f x < f y) (h : xs ys) :

View File

@@ -19,12 +19,9 @@ public import Init.Data.Int.LemmasAux
public import Init.Data.Int.Pow
public import Init.Data.Int.LemmasAux
public import Init.Data.BitVec.Bootstrap
public import Init.Data.Order.Factories
public section
open Std
set_option linter.missingDocs true
namespace BitVec
@@ -4018,16 +4015,6 @@ protected theorem ne_of_lt {x y : BitVec n} : x < y → x ≠ y := by
simp only [lt_def, ne_eq, toNat_eq]
apply Nat.ne_of_lt
instance instIsLinearOrder : IsLinearOrder (BitVec n) := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply BitVec.le_antisymm
case le_trans => constructor; apply BitVec.le_trans
case le_total => constructor; apply BitVec.le_total
instance instLawfulOrderLT : LawfulOrderLT (BitVec n) := by
apply LawfulOrderLT.of_le
simpa using fun _ _ => BitVec.lt_asymm
protected theorem umod_lt (x : BitVec n) {y : BitVec n} : 0 < y x % y < y := by
simp only [ofNat_eq_ofNat, lt_def, toNat_ofNat, Nat.zero_mod]
apply Nat.mod_lt

View File

@@ -8,6 +8,5 @@ module
prelude
public import Init.Data.Char.Basic
public import Init.Data.Char.Lemmas
public import Init.Data.Char.Order
public section

View File

@@ -61,7 +61,6 @@ instance leTotal : Std.Total (· ≤ · : Char → Char → Prop) where
total := Char.le_total
-- This instance is useful while setting up instances for `String`.
@[deprecated ltAsymm (since := "2025-08-01")]
def notLTTotal : Std.Total (¬ · < · : Char Char Prop) where
total := fun x y => by simpa using Char.le_total y x

View File

@@ -1,27 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Char.Basic
import Init.Data.Char.Lemmas
public import Init.Data.Order.Factories
open Std
namespace Char
public instance instIsLinearOrder : IsLinearOrder Char := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Char.le_antisymm
case le_trans => constructor; apply Char.le_trans
case le_total => constructor; apply Char.le_total
public instance : LawfulOrderLT Char where
lt_iff a b := by
simp [ Char.not_le, Decidable.imp_iff_not_or, Std.Total.total]
end Char

View File

@@ -12,13 +12,9 @@ public import Init.Ext
public import Init.ByCases
public import Init.Conv
public import Init.Omega
public import Init.Data.Order.Factories
import Init.Data.Order.Lemmas
public section
open Std
namespace Fin
@[simp] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
@@ -255,16 +251,6 @@ protected theorem le_antisymm_iff {x y : Fin n} : x = y ↔ x ≤ y ∧ y ≤ x
protected theorem le_antisymm {x y : Fin n} (h1 : x y) (h2 : y x) : x = y :=
Fin.le_antisymm_iff.2 h1, h2
instance instIsLinearOrder : IsLinearOrder (Fin n) := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Fin.le_antisymm
case le_total => constructor; apply Fin.le_total
case le_trans => constructor; apply Fin.le_trans
instance : LawfulOrderLT (Fin n) where
lt_iff := by
simp [ Fin.not_le, Decidable.imp_iff_not_or, Std.Total.total]
@[simp, grind =] theorem val_rev (i : Fin n) : rev i = n - (i + 1) := rfl
@[simp] theorem rev_rev (i : Fin n) : rev (rev i) = i := Fin.ext <| by

View File

@@ -956,12 +956,6 @@ theorem neg_mul_ediv_cancel_left (a b : Int) (h : a ≠ 0) : -(a * b) / a = -b :
@[simp] theorem emod_one (a : Int) : a % 1 = 0 := by
simp [emod_def, Int.one_mul, Int.sub_self]
theorem ediv_minus_one (a : Int) : a / (-1) = -a := by
simp
theorem emod_minus_one (a : Int) : a % (-1) = 0 := by
simp
@[deprecated sub_emod_right (since := "2025-04-11")]
theorem emod_sub_cancel (x y : Int) : (x - y) % y = x % y :=
sub_emod_right ..

View File

@@ -2121,29 +2121,6 @@ theorem not_le_of_le (ctx : Context) (p₁ p₂ : Poly) : not_le_of_le_cert p₁
have := not_le_of_le' ctx p₁ p₂ h 0 h₁; simp at this
simp [*]
theorem natCast_sub (x y : Nat)
: (NatCast.natCast (x - y) : Int)
=
if (NatCast.natCast y : Int) + (-1)*NatCast.natCast x 0 then
(NatCast.natCast x : Int) + -1*NatCast.natCast y
else
(0 : Int) := by
change ((x - y) : Int) = if (y : Int) + (-1)*x 0 then (x : Int) + (-1)*y else 0
rw [Int.neg_mul, Int.sub_eq_add_neg, Int.one_mul]
rw [Int.neg_mul, Int.sub_eq_add_neg, Int.one_mul]
split
next h =>
replace h := Int.le_of_sub_nonpos h
rw [Int.ofNat_le] at h
rw [Int.ofNat_sub h]
next h =>
have : ¬ (y : Int) x := by
intro h
replace h := Int.sub_nonpos_of_le h
contradiction
rw [Int.ofNat_le] at this
rw [Lean.Omega.Int.ofNat_sub_eq_zero this]
end Int.Linear
theorem Int.not_le_eq (a b : Int) : (¬a b) = (b + 1 a) := by

View File

@@ -8,13 +8,9 @@ module
prelude
public import Init.Data.Int.Lemmas
public import Init.ByCases
public import Init.Data.Order.Factories
import Init.Data.Order.Lemmas
public section
open Std
/-!
# Results about the order properties of the integers, and the integers as an ordered ring.
-/
@@ -1419,14 +1415,4 @@ theorem natAbs_eq_iff_mul_eq_zero : natAbs a = n ↔ (a - n) * (a + n) = 0 := by
@[deprecated natAbs_eq_iff_mul_eq_zero (since := "2025-03-11")]
abbrev eq_natAbs_iff_mul_eq_zero := @natAbs_eq_iff_mul_eq_zero
instance instIsLinearOrder : IsLinearOrder Int := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Int.le_antisymm
case le_total => constructor; apply Int.le_total
case le_trans => constructor; apply Int.le_trans
instance : LawfulOrderLT Int where
lt_iff := by
simp [ Int.not_le, Decidable.imp_iff_not_or, Std.Total.total]
end Int

View File

@@ -7,7 +7,7 @@ module
prelude
public import Init.Control.Lawful.Basic
public import Init.Data.Subtype.Basic
public import Init.Data.Subtype
public import Init.PropLemmas
public section

View File

@@ -8,7 +8,7 @@ module
prelude
public import all Init.Data.List.Lemmas -- for dsimping with `getElem?_cons_succ`
public import Init.Data.List.Count
public import Init.Data.Subtype.Basic
public import Init.Data.Subtype
public import Init.BinderNameHint
public section

View File

@@ -2108,11 +2108,6 @@ def range' : (start len : Nat) → (step : Nat := 1) → List Nat
| _, 0, _ => []
| s, n+1, step => s :: range' (s+step) n step
@[simp, grind =] theorem range'_zero : range' s 0 step = [] := rfl
@[simp, grind =] theorem range'_one {s step : Nat} : range' s 1 step = [s] := rfl
-- The following theorem is intentionally not a simp lemma.
theorem range'_succ : range' s (n + 1) step = s :: range' (s + step) n step := rfl
/-! ### zipIdx -/
/--

View File

@@ -70,7 +70,7 @@ See also
Further results, which first require developing further automation around `Nat`, appear in
* `Init.Data.List.Nat.Basic`: miscellaneous lemmas
* `Init.Data.List.Nat.Range`: `List.range`, `List.range'` and `List.enum`
* `Init.Data.List.Nat.Range`: `List.range` and `List.enum`
* `Init.Data.List.Nat.TakeDrop`: `List.take` and `List.drop`
Also
@@ -1084,12 +1084,6 @@ theorem getLast?_tail {l : List α} : (tail l).getLast? = if l.length = 1 then n
rw [if_neg]
rintro
@[simp, grind =]
theorem cons_head_tail (h : l []) : l.head h :: l.tail = l := by
induction l with
| nil => contradiction
| cons ih => simp_all
/-! ## Basic operations -/
/-! ### map -/
@@ -1857,10 +1851,6 @@ theorem append_eq_map_iff {f : α → β} :
theorem sum_append_nat {l₁ l₂ : List Nat} : (l₁ ++ l₂).sum = l₁.sum + l₂.sum := by
induction l₁ generalizing l₂ <;> simp_all [Nat.add_assoc]
@[simp, grind =]
theorem sum_reverse_nat (xs : List Nat) : xs.reverse.sum = xs.sum := by
induction xs <;> simp_all [Nat.add_comm]
/-! ### concat
Note that `concat_eq_append` is a `@[simp]` lemma, so `concat` should usually not appear in goals.

View File

@@ -8,13 +8,9 @@ module
prelude
public import Init.Data.List.Lemmas
public import Init.Data.List.Nat.TakeDrop
public import Init.Data.Order.Factories
import Init.Data.Order.Lemmas
public section
open Std
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
@@ -22,11 +18,6 @@ namespace List
/-! ### Lexicographic ordering -/
instance [LT α] [Std.Asymm (α := List α) (· < ·)] : LawfulOrderLT (List α) where
lt_iff := by
simp only [LE.le, List.le, Classical.not_not, iff_and_self]
apply Std.Asymm.asymm
@[simp] theorem lex_lt [LT α] {l₁ l₂ : List α} : Lex (· < ·) l₁ l₂ l₁ < l₂ := Iff.rfl
@[simp] theorem not_lex_lt [LT α] {l₁ l₂ : List α} : ¬ Lex (· < ·) l₁ l₂ l₂ l₁ := Iff.rfl
@@ -88,6 +79,7 @@ theorem not_cons_lex_cons_iff [DecidableEq α] [DecidableRel r] {a b} {l₁ l₂
rw [cons_lex_cons_iff, not_or, Decidable.not_and_iff_or_not, and_or_left]
theorem cons_le_cons_iff [LT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
{a b} {l₁ l₂ : List α} :
@@ -109,22 +101,19 @@ theorem cons_le_cons_iff [LT α]
exact i₂.antisymm _ _ h₃ h₁, h₂
· rintro (h | h₁, h₂)
· left
exact i₁.asymm _ _ h, fun w => Irrefl.irrefl _ (w h)
exact i₁.asymm _ _ h, fun w => i₀.irrefl _ (w h)
· right
exact fun w => Irrefl.irrefl _ (h₁ w), h₂
exact fun w => i₀.irrefl _ (h₁ w), h₂
theorem not_lt_of_cons_le_cons [LT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
{a b : α} {l₁ l₂ : List α} (h : a :: l₁ b :: l₂) : ¬ b < a := by
rw [cons_le_cons_iff] at h
rcases h with h | rfl, h
· exact i₁.asymm _ _ h
· exact Irrefl.irrefl _
theorem left_le_left_of_cons_le_cons [LT α] [LE α] [IsLinearOrder α]
[LawfulOrderLT α] {a b : α} {l₁ l₂ : List α} (h : a :: l₁ b :: l₂) : a b := by
simpa [not_lt] using not_lt_of_cons_le_cons h
· exact i₀.irrefl _
theorem le_of_cons_le_cons [LT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
@@ -176,7 +165,11 @@ instance [LT α] [Trans (· < · : αα → Prop) (· < ·) (· < ·)] :
protected theorem lt_of_le_of_lt [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
protected theorem lt_of_le_of_lt [LT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : List α} (h₁ : l₁ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ := by
induction h₂ generalizing l₁ with
| nil => simp_all
@@ -186,8 +179,11 @@ protected theorem lt_of_le_of_lt [LT α] [LE α] [IsLinearOrder α] [LawfulOrder
| nil => simp_all
| cons c l₁ =>
apply Lex.rel
replace h₁ := left_le_left_of_cons_le_cons h₁
exact lt_of_le_of_lt h₁ hab
replace h₁ := not_lt_of_cons_le_cons h₁
apply Classical.byContradiction
intro h₂
have := i₃.trans h₁ h₂
contradiction
| cons w₃ ih =>
rename_i a as bs
cases l₁ with
@@ -197,34 +193,21 @@ protected theorem lt_of_le_of_lt [LT α] [LE α] [IsLinearOrder α] [LawfulOrder
by_cases w₅ : a = c
· subst w₅
exact Lex.cons (ih (le_of_cons_le_cons h₁))
· simp only [not_lt] at w₄
exact Lex.rel (lt_of_le_of_ne w₄ (w₅.imp Eq.symm))
· exact Lex.rel (Classical.byContradiction fun w₆ => w₅ (i₂.antisymm _ _ w₄ w₆))
@[deprecated List.lt_of_le_of_lt (since := "2025-08-01")]
protected theorem lt_of_le_of_lt' [LT α]
protected theorem le_trans [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : List α} (h₁ : l₁ l₂) (h₂ : l₂ < l₃) : l₁ < l₃ :=
letI : LE α := .ofLT α
haveI : IsLinearOrder α := IsLinearOrder.of_lt
List.lt_of_le_of_lt h₁ h₂
protected theorem le_trans [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
{l₁ l₂ l₃ : List α} (h₁ : l₁ l₂) (h₂ : l₂ l₃) : l₁ l₃ :=
fun h₃ => h₁ (List.lt_of_le_of_lt h₂ h₃)
@[deprecated List.le_trans (since := "2025-08-01")]
protected theorem le_trans' [LT α]
instance [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{l₁ l₂ l₃ : List α} (h₁ : l₁ l₂) (h₂ : l₂ l₃) : l₁ l₃ :=
letI := LE.ofLT α
haveI : IsLinearOrder α := IsLinearOrder.of_lt
List.le_trans h₁ h₂
instance [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α] :
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)] :
Trans (· · : List α List α Prop) (· ·) (· ·) where
trans h₁ h₂ := List.le_trans h₁ h₂
@@ -264,21 +247,14 @@ theorem not_lex_total {r : αα → Prop}
obtain (_ | _) := not_lex_total h l₁ l₂ <;> contradiction
protected theorem le_total [LT α]
[i : Std.Asymm (· < · : α α Prop)] (l₁ l₂ : List α) : l₁ l₂ l₂ l₁ :=
not_lex_total i.total_not.total l₂ l₁
[i : Std.Total (¬ · < · : α α Prop)] (l₁ l₂ : List α) : l₁ l₂ l₂ l₁ :=
not_lex_total i.total l₂ l₁
protected theorem le_total_of_asymm [LT α]
[i : Std.Asymm (· < · : α α Prop)] (l₁ l₂ : List α) : l₁ l₂ l₂ l₁ :=
List.le_total l₁ l₂
instance [LT α] [Std.Asymm (· < · : α α Prop)] :
instance [LT α]
[Std.Total (¬ · < · : α α Prop)] :
Std.Total (· · : List α List α Prop) where
total := List.le_total
@[no_expose]
instance instIsLinearOrder [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α] :
IsLinearOrder (List α) := IsLinearOrder.of_le
@[simp] protected theorem not_lt [LT α]
{l₁ l₂ : List α} : ¬ l₁ < l₂ l₂ l₁ := Iff.rfl
@@ -286,7 +262,7 @@ instance instIsLinearOrder [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
{l₁ l₂ : List α} : ¬ l₂ l₁ l₁ < l₂ := Classical.not_not
protected theorem le_of_lt [LT α]
[i : Std.Asymm (· < · : α α Prop)]
[i : Std.Total (¬ · < · : α α Prop)]
{l₁ l₂ : List α} (h : l₁ < l₂) : l₁ l₂ := by
obtain (h' | h') := List.le_total l₁ l₂
· exact h'
@@ -296,7 +272,7 @@ protected theorem le_of_lt [LT α]
protected theorem le_iff_lt_or_eq [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Total (¬ · < · : α α Prop)]
{l₁ l₂ : List α} : l₁ l₂ l₁ < l₂ l₁ = l₂ := by
constructor
· intro h
@@ -480,6 +456,7 @@ protected theorem lt_iff_exists [LT α] {l₁ l₂ : List α} :
simp
protected theorem le_iff_exists [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)] {l₁ l₂ : List α} :
l₁ l₂
@@ -503,6 +480,7 @@ theorem append_left_lt [LT α] {l₁ l₂ l₃ : List α} (h : l₂ < l₃) :
| cons a l₁ ih => simp [cons_lt_cons_iff, ih]
theorem append_left_le [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
{l₁ l₂ l₃ : List α} (h : l₂ l₃) :
@@ -536,8 +514,10 @@ protected theorem map_lt [LT α] [LT β]
simp [cons_lt_cons_iff, w, h]
protected theorem map_le [LT α] [LT β]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Irrefl (· < · : β β Prop)]
[Std.Asymm (· < · : β β Prop)]
[Std.Antisymm (¬ · < · : β β Prop)]
{l₁ l₂ : List α} {f : α β} (w : x y, x < y f x < f y) (h : l₁ l₂) :

View File

@@ -8,14 +8,9 @@ module
prelude
public import Init.Data.List.Lemmas
public import Init.Data.List.Pairwise
public import Init.Data.Order.Factories
public import Init.Data.Subtype.Order
import Init.Data.Order.Lemmas
public section
open Std
/-!
# Lemmas about `List.min?` and `List.max?.
-/
@@ -60,7 +55,7 @@ theorem min?_eq_head? {α : Type u} [Min α] {l : List α}
have hx : min x y = x := rel_of_pairwise_cons h mem_cons_self
rw [foldl_cons, ih _ (hx.symm h.sublist (by simp)), hx]
theorem min?_mem [Min α] [MinEqOr α] :
theorem min?_mem [Min α] (min_eq_or : a b : α, min a b = a min a b = b) :
{xs : List α} xs.min? = some a a xs := by
intro xs
match xs with
@@ -77,10 +72,13 @@ theorem min?_mem [Min α] [MinEqOr α] :
have p := ind _ eq
cases p with
| inl p =>
cases MinEqOr.min_eq_or x y with | _ q => simp [p, q]
cases min_eq_or x y with | _ q => simp [p, q]
| inr p => simp [p, mem_cons]
theorem le_min?_iff [Min α] [LE α] [LawfulOrderInf α] :
-- See also `Init.Data.List.Nat.Basic` for specialisations of the next two results to `Nat`.
theorem le_min?_iff [Min α] [LE α]
(le_min_iff : a b c : α, a min b c a b a c) :
{xs : List α} xs.min? = some a {x}, x a b, b xs x b
| nil => by simp
| cons x xs => by
@@ -95,60 +93,34 @@ theorem le_min?_iff [Min α] [LE α] [LawfulOrderInf α] :
simp at eq
simp [ih _ eq, le_min_iff, and_assoc]
theorem min?_eq_some_iff [Min α] [LE α] {xs : List α} [IsLinearOrder α] [LawfulOrderMin α] :
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `min_eq_or`,
-- and `le_min_iff`.
theorem min?_eq_some_iff [Min α] [LE α]
(le_refl : a : α, a a)
(min_eq_or : a b : α, min a b = a min a b = b)
(le_min_iff : a b c : α, a min b c a b a c) {xs : List α}
(anti : a b, a xs b xs a b b a a = b := by
exact fun a b _ _ => Std.Antisymm.antisymm a b) :
xs.min? = some a a xs b, b xs a b := by
refine fun h => min?_mem h, (le_min?_iff h).1 (le_refl _), ?_
refine fun h => min?_mem min_eq_or h, (le_min?_iff le_min_iff h).1 (le_refl _), ?_
intro h₁, h₂
cases xs with
| nil => simp at h₁
| cons x xs =>
rw [List.min?]
exact congrArg some <| le_antisymm
((le_min?_iff (xs := x :: xs) rfl).1 (le_refl _) _ h₁)
(h₂ _ (min?_mem (xs := x :: xs) rfl))
exact congrArg some <| anti _ _ (min?_mem min_eq_or rfl) h₁
((le_min?_iff le_min_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
(h₂ _ (min?_mem min_eq_or (xs := x::xs) rfl))
private theorem min?_attach [Min α] [MinEqOr α] {xs : List α} :
xs.attach.min? = (xs.min?.pmap (fun m hm => m, min?_mem hm) (fun _ => id)) := by
cases xs with
| nil => simp
| cons x xs =>
simp only [min?, attach_cons, Option.some.injEq, Option.pmap_some]
rw [foldl_map]
simp only [Subtype.ext_iff]
rw [ foldl_attach (l := xs)]
apply Eq.trans (foldl_hom (f := Subtype.val) ?_).symm
· rfl
· intros; rfl
theorem min?_eq_min?_attach [Min α] [MinEqOr α] {xs : List α} :
xs.min? = (xs.attach.min?.map Subtype.val) := by
simp [min?_attach, Option.map_pmap]
theorem min?_eq_some_iff_subtype [Min α] [LE α] {xs : List α}
[MinEqOr α] [IsLinearOrder (Subtype (· xs))] [LawfulOrderMin (Subtype (· xs))] :
xs.min? = some a a xs b, b xs a b := by
have := fun a => min?_eq_some_iff (xs := xs.attach) (a := a)
rw [min?_eq_min?_attach]
simp [min?_eq_some_iff]
constructor
· rintro ha, h
exact ha, h
· rintro ha, h
exact ha, h
theorem min?_replicate [Min α] [Std.IdempotentOp (min : α α α)] {n : Nat} {a : α} :
theorem min?_replicate [Min α] {n : Nat} {a : α} (w : min a a = a) :
(replicate n a).min? = if n = 0 then none else some a := by
induction n with
| zero => rfl
| succ n ih => cases n <;> simp_all [replicate_succ, min?_cons', Std.IdempotentOp.idempotent]
| succ n ih => cases n <;> simp_all [replicate_succ, min?_cons']
@[simp] theorem min?_replicate_of_pos [Min α] [MinEqOr α] {n : Nat} {a : α} (h : 0 < n) :
@[simp] theorem min?_replicate_of_pos [Min α] {n : Nat} {a : α} (w : min a a = a) (h : 0 < n) :
(replicate n a).min? = some a := by
simp [min?_replicate, Nat.ne_of_gt h]
simp [min?_replicate, Nat.ne_of_gt h, w]
/--
Requirements are satisfied for `[OrderData α] [Min α] [IsLinearOrder α] [LawfulOrderMin α]`
-/
theorem foldl_min [Min α] [Std.IdempotentOp (min : α α α)] [Std.Associative (min : α α α)]
{l : List α} {a : α} : l.foldl (init := a) min = min a (l.min?.getD a) := by
cases l <;> simp [min?, foldl_assoc, Std.IdempotentOp.idempotent]
@@ -172,120 +144,54 @@ theorem isSome_max?_of_mem {l : List α} [Max α] {a : α} (h : a ∈ l) :
l.max?.isSome := by
cases l <;> simp_all [max?_cons']
theorem max?_eq_head? {α : Type u} [Max α] {l : List α}
(h : l.Pairwise (fun a b => max a b = a)) : l.max? = l.head? := by
cases l with
| nil => rfl
| cons x l =>
rw [head?_cons, max?_cons', Option.some.injEq]
induction l generalizing x with
| nil => simp
| cons y l ih =>
have hx : max x y = x := rel_of_pairwise_cons h mem_cons_self
rw [foldl_cons, ih _ (hx.symm h.sublist (by simp)), hx]
theorem max?_mem [Max α] [MaxEqOr α] :
{xs : List α} xs.max? = some a a xs := by
intro xs
match xs with
| nil => simp
| x :: xs =>
simp only [max?_cons', Option.some.injEq, mem_cons]
intro eq
induction xs generalizing x with
| nil =>
simp at eq
simp [eq]
| cons y xs ind =>
simp at eq
have p := ind _ eq
cases p with
| inl p =>
cases MaxEqOr.max_eq_or x y with | _ q => simp [p, q]
| inr p => simp [p, mem_cons]
theorem max?_le_iff [Max α] [LE α] [LawfulOrderSup α] :
{xs : List α} xs.max? = some a {x}, a x b, b xs b x
theorem max?_mem [Max α] (min_eq_or : a b : α, max a b = a max a b = b) :
{xs : List α} xs.max? = some a a xs
| nil => by simp
| cons x xs => by
rw [max?]
intro eq y
simp only [Option.some.injEq] at eq
rw [max?]; rintro
induction xs generalizing x with simp at *
| cons y xs ih =>
rcases ih (max x y) with h | h <;> simp [h]
simp [ or_assoc, min_eq_or x y]
-- See also `Init.Data.List.Nat.Basic` for specialisations of the next two results to `Nat`.
theorem max?_le_iff [Max α] [LE α]
(max_le_iff : a b c : α, max b c a b a c a) :
{xs : List α} xs.max? = some a {x}, a x b xs, b x
| nil => by simp
| cons x xs => by
rw [max?]; rintro y
induction xs generalizing x with
| nil =>
simp at eq
simp [eq]
| cons z xs ih =>
simp at eq
simp [ih _ eq, max_le_iff, and_assoc]
| nil => simp
| cons y xs ih => simp [ih, max_le_iff, and_assoc]
theorem max?_eq_some_iff [Max α] [LE α] {xs : List α} [IsLinearOrder (α)]
[LawfulOrderMax α] : xs.max? = some a a xs b, b xs b a := by
refine fun h => max?_mem h, (max?_le_iff h).1 (le_refl _), ?_
intro h₁, h₂
cases xs with
| nil => simp at h₁
| cons x xs =>
rw [List.max?]
exact congrArg some <| le_antisymm
(h₂ _ (max?_mem (xs := x :: xs) rfl))
((max?_le_iff (xs := x :: xs) rfl).1 (le_refl _) _ h₁)
private theorem max?_attach [Max α] [MaxEqOr α] {xs : List α} :
xs.attach.max? = (xs.max?.pmap (fun m hm => m, max?_mem hm) (fun _ => id)) := by
cases xs with
| nil => simp
| cons x xs =>
simp only [max?, attach_cons, Option.some.injEq, Option.pmap_some]
rw [foldl_map]
simp only [Subtype.ext_iff]
rw [ foldl_attach (l := xs)]
apply Eq.trans (foldl_hom (f := Subtype.val) ?_).symm
· rfl
· intros; rfl
theorem max?_eq_max?_attach [Max α] [MaxEqOr α] {xs : List α} :
xs.max? = (xs.attach.max?.map Subtype.val) := by
simp [max?_attach, Option.map_pmap]
theorem max?_eq_some_iff_subtype [Max α] [LE α] {xs : List α}
[MaxEqOr α] [IsLinearOrder (Subtype (· xs))]
[LawfulOrderMax (Subtype (· xs))] :
xs.max? = some a a xs b, b xs b a := by
have := fun a => max?_eq_some_iff (xs := xs.attach) (a := a)
rw [max?_eq_max?_attach]
simp [max?_eq_some_iff]
constructor
· rintro ha, h
exact ha, h
· rintro ha, h
exact ha, h
@[deprecated max?_eq_some_iff (since := "2025-08-01")]
theorem max?_eq_some_iff_legacy [Max α] [LE α] [anti : Std.Antisymm (· · : α α Prop)]
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `max_eq_or`,
-- and `le_min_iff`.
theorem max?_eq_some_iff [Max α] [LE α] [anti : Std.Antisymm (· · : α α Prop)]
(le_refl : a : α, a a)
(max_eq_or : a b : α, max a b = a max a b = b)
(max_le_iff : a b c : α, max b c a b a c a) {xs : List α} :
xs.max? = some a a xs b xs, b a := by
haveI : MaxEqOr α := max_eq_or
haveI : LawfulOrderMax α := .of_le (fun _ _ _ => max_le_iff _ _ _) max_eq_or
haveI : Refl (α := α) (· ·) := le_refl
haveI : IsLinearOrder α := .of_refl_of_antisymm_of_lawfulOrderMax
apply max?_eq_some_iff
refine fun h => max?_mem max_eq_or h, (max?_le_iff max_le_iff h).1 (le_refl _), ?_
intro h₁, h₂
cases xs with
| nil => simp at h₁
| cons x xs =>
exact congrArg some <| anti.1 _ _
(h₂ _ (max?_mem max_eq_or (xs := x::xs) rfl))
((max?_le_iff max_le_iff (xs := x::xs) rfl).1 (le_refl _) _ h₁)
theorem max?_replicate [Max α] [Std.IdempotentOp (max : α α α)] {n : Nat} {a : α} :
theorem max?_replicate [Max α] {n : Nat} {a : α} (w : max a a = a) :
(replicate n a).max? = if n = 0 then none else some a := by
induction n with
| zero => rfl
| succ n ih => cases n <;> simp_all [replicate_succ, max?_cons', Std.IdempotentOp.idempotent]
| succ n ih => cases n <;> simp_all [replicate_succ, max?_cons']
@[simp] theorem max?_replicate_of_pos [Max α] [MaxEqOr α] {n : Nat} {a : α} (h : 0 < n) :
@[simp] theorem max?_replicate_of_pos [Max α] {n : Nat} {a : α} (w : max a a = a) (h : 0 < n) :
(replicate n a).max? = some a := by
simp [max?_replicate, Nat.ne_of_gt h]
simp [max?_replicate, Nat.ne_of_gt h, w]
/--
Requirements are satisfied for `[OrderData α] [Max α] [LinearOrder α] [LawfulOrderMax α]`
-/
theorem foldl_max [Max α] [Std.IdempotentOp (max : α α α)] [Std.Associative (max : α α α)]
{l : List α} {a : α} : l.foldl (init := a) max = max a (l.max?.getD a) := by
cases l <;> simp [max?, foldl_assoc, Std.IdempotentOp.idempotent]

View File

@@ -10,7 +10,6 @@ public import Init.Data.List.Count
public import Init.Data.List.Find
public import Init.Data.List.MinMax
public import Init.Data.Nat.Lemmas
import Init.Data.Nat.Order
public section
@@ -211,10 +210,12 @@ theorem mem_eraseIdx_iff_getElem? {x : α} {l} {k} : x ∈ eraseIdx l k ↔ ∃
/-! ### min? -/
-- A specialization of `min?_eq_some_iff` to Nat.
@[deprecated min?_eq_some_iff (since := "2025-08-08")]
theorem min?_eq_some_iff' {xs : List Nat} :
xs.min? = some a (a xs b xs, a b) := by
exact min?_eq_some_iff
xs.min? = some a (a xs b xs, a b) :=
min?_eq_some_iff
(le_refl := Nat.le_refl)
(min_eq_or := fun _ _ => Nat.min_def .. by split <;> simp)
(le_min_iff := fun _ _ _ => Nat.le_min)
theorem min?_get_le_of_mem {l : List Nat} {a : Nat} (h : a l) :
l.min?.get (isSome_min?_of_mem h) a := by
@@ -236,10 +237,12 @@ theorem min?_getD_le_of_mem {l : List Nat} {a k : Nat} (h : a ∈ l) : l.min?.ge
/-! ### max? -/
-- A specialization of `max?_eq_some_iff` to Nat.
@[deprecated max?_eq_some_iff (since := "2025-08-08")]
theorem max?_eq_some_iff' {xs : List Nat} :
xs.max? = some a (a xs b xs, b a) :=
max?_eq_some_iff
(le_refl := Nat.le_refl)
(max_eq_or := fun _ _ => Nat.max_def .. by split <;> simp)
(max_le_iff := fun _ _ _ => Nat.max_le)
theorem le_max?_get_of_mem {l : List Nat} {a : Nat} (h : a l) :
a l.max?.get (isSome_max?_of_mem h) := by

View File

@@ -90,27 +90,28 @@ theorem map_sub_range' {a s : Nat} (h : a ≤ s) (n : Nat) :
rintro rfl
omega
theorem range'_eq_append_iff : range' s n step = xs ++ ys k, k n xs = range' s k step ys = range' (s + k * step) (n - k) step := by
theorem range'_eq_append_iff : range' s n = xs ++ ys k, k n xs = range' s k ys = range' (s + k) (n - k) := by
induction n generalizing s xs ys with
| zero => simp
| succ n ih =>
simp only [range'_succ]
rw [cons_eq_append_iff]
have add_mul' (k n m : Nat) : (n + m) * k = m * k + n * k := by rw [Nat.add_mul]; omega
constructor
· rintro (rfl, rfl | _, rfl, h)
· exact 0, by simp [range'_succ]
· simp only [ih] at h
obtain k, h, rfl, rfl := h
refine k + 1, ?_
simp_all [range'_succ, Nat.add_assoc]
simp_all [range'_succ]
omega
· rintro k, h, rfl, rfl
cases k with
| zero => simp [range'_succ]
| succ k =>
simp only [range'_succ, reduceCtorEq, false_and, cons.injEq, true_and, ih, exists_eq_left', false_or]
simp only [range'_succ, reduceCtorEq, false_and, cons.injEq, true_and, ih, range'_inj, exists_eq_left', or_true, and_true, false_or]
refine k, ?_
simp_all [Nat.add_assoc]
simp_all
omega
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat Bool} :
(range' s n).find? p = some i p i i range' s n j, s j j < i !p j := by
@@ -177,46 +178,6 @@ theorem count_range_1' {a s n} :
specialize h (a - s)
omega
@[simp, grind =]
theorem sum_range' : (range' start n step).sum = n * start + n * (n - 1) * step / 2 := by
induction n generalizing start with
| zero => simp
| succ n ih =>
simp_all only [List.range'_succ, List.sum_cons, Nat.mul_add, Nat.add_assoc,
Nat.add_mul, Nat.one_mul, Nat.add_one_sub_one]
have : n * step + n * (n - 1) * step / 2 = (n * n * step + n * step) / 2 := by
apply Nat.eq_div_of_mul_eq_left (by omega)
rw [Nat.add_mul, Nat.div_mul_cancel]
· calc n * step * 2 + n * (n - 1) * step
_ = n * step * 2 + n * step * (n - 1) := by simp [Nat.mul_comm, Nat.mul_assoc]
_ = n * step + n * step * n := by cases n <;> simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
_ = n * n * step + n * step := by simp [Nat.mul_comm, Nat.add_comm, Nat.mul_left_comm]
· have : 2 n 2 (n - 1) := by omega
apply Nat.dvd_mul_right_of_dvd
apply Nat.dvd_mul.mpr
cases this with
| inl h => exists 2, 1; omega
| inr h => exists 1, 2; omega
omega
@[simp, grind =]
theorem drop_range' : (List.range' start n step).drop k = List.range' (start + k * step) (n - k) step := by
induction k generalizing start n with
| zero => simp
| succ => cases n <;> simp [*, List.range'_succ, Nat.add_mul, Nat.add_assoc, Nat.add_right_comm]
@[simp, grind =]
theorem take_range'_of_length_le (h : n k) : (List.range' start n step).take k = List.range' start n step := by
induction n generalizing start k with
| zero => simp
| succ n ih => cases k <;> simp_all [List.range'_succ]
@[simp, grind =]
theorem take_range'_of_length_ge (h : n k) : (List.range' start n step).take k = List.range' start k step := by
induction k generalizing start n with
| zero => simp
| succ k ih => cases n <;> simp_all [List.range'_succ]
/-! ### range -/
theorem reverse_range' : {s n : Nat}, reverse (range' s n) = map (s + n - 1 - ·) (range n)
@@ -394,7 +355,9 @@ theorem zipIdx_eq_append_iff {l : List α} {k : Nat} :
simp only [length_range'] at h
obtain rfl := h
refine ws, xs, rfl, ?_
simp [zipIdx_eq_zip_range', length_append]
simp only [zipIdx_eq_zip_range', length_append, true_and]
congr
omega
· rintro l₁', l₂', rfl, rfl, rfl
simp only [zipIdx_eq_zip_range']
refine l₁', l₂', range' k l₁'.length, range' (k + l₁'.length) l₂'.length, ?_

View File

@@ -29,31 +29,30 @@ open Nat
/-! ### range' -/
@[simp, grind =] theorem length_range' {s step} : {n : Nat}, length (range' s n step) = n
theorem range'_succ {s n step} : range' s (n + 1) step = s :: range' (s + step) n step := by
simp [range']
@[simp] theorem length_range' {s step} : {n : Nat}, length (range' s n step) = n
| 0 => rfl
| _ + 1 => congrArg succ length_range'
@[simp, grind =] theorem range'_eq_nil_iff : range' s n step = [] n = 0 := by
@[simp] theorem range'_eq_nil_iff : range' s n step = [] n = 0 := by
rw [ length_eq_zero_iff, length_range']
theorem range'_ne_nil_iff (s : Nat) {n step : Nat} : range' s n step [] n 0 := by
cases n <;> simp
theorem range'_eq_cons_iff : range' s n step = a :: xs s = a 0 < n xs = range' (a + step) (n - 1) step := by
induction n generalizing s with
| zero => simp
| succ n ih =>
simp only [range'_succ]
simp only [cons.injEq, and_congr_right_iff]
rintro rfl
simp [eq_comm]
@[simp] theorem range'_zero : range' s 0 step = [] := by
simp
@[simp, grind =] theorem tail_range' : (range' s n step).tail = range' (s + step) (n - 1) step := by
@[simp] theorem range'_one {s step : Nat} : range' s 1 step = [s] := rfl
@[simp] theorem tail_range' : (range' s n step).tail = range' (s + step) (n - 1) step := by
cases n with
| zero => simp
| succ n => simp [range'_succ]
@[simp, grind =] theorem range'_inj : range' s n = range' s' n' n = n' (n = 0 s = s') := by
@[simp] theorem range'_inj : range' s n = range' s' n' n = n' (n = 0 s = s') := by
constructor
· intro h
have h' := congrArg List.length h
@@ -82,14 +81,14 @@ theorem getElem?_range' {s step} :
exact (getElem?_range' (s := s + step) (by exact succ_lt_succ_iff.mp h)).trans <| by
simp [Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
@[simp, grind =] theorem getElem_range' {n m step} {i} (H : i < (range' n m step).length) :
@[simp] theorem getElem_range' {n m step} {i} (H : i < (range' n m step).length) :
(range' n m step)[i] = n + step * i :=
(getElem?_eq_some_iff.1 <| getElem?_range' (by simpa using H)).2
theorem head?_range' : (range' s n).head? = if n = 0 then none else some s := by
induction n <;> simp_all [range'_succ]
@[simp, grind =] theorem head_range' (h) : (range' s n).head h = s := by
@[simp] theorem head_range' (h) : (range' s n).head h = s := by
repeat simp_all [head?_range', head_eq_iff_head?_eq_some]
theorem map_add_range' {a} : s n step, map (a + ·) (range' s n step) = range' (a + s) n step
@@ -108,7 +107,7 @@ theorem range'_append : ∀ {s m n step : Nat},
simpa [range', Nat.mul_succ, Nat.add_assoc, Nat.add_comm]
using range'_append (s := s + step)
@[simp, grind =] theorem range'_append_1 {s m n : Nat} :
@[simp] theorem range'_append_1 {s m n : Nat} :
range' s m ++ range' (s + m) n = range' s (m + n) := by simpa using range'_append (step := 1)
theorem range'_sublist_right {s m n : Nat} : range' s m step <+ range' s n step m n :=
@@ -130,6 +129,15 @@ theorem range'_concat {s n : Nat} : range' s (n + 1) step = range' s n step ++ [
theorem range'_1_concat {s n : Nat} : range' s (n + 1) = range' s n ++ [s + n] := by
simp [range'_concat]
theorem range'_eq_cons_iff : range' s n = a :: xs s = a 0 < n xs = range' (a + 1) (n - 1) := by
induction n generalizing s with
| zero => simp
| succ n ih =>
simp only [range'_succ]
simp only [cons.injEq, and_congr_right_iff]
rintro rfl
simp [eq_comm]
/-! ### range -/
@[simp, grind =] theorem range_one : range 1 = [0] := rfl
@@ -144,7 +152,7 @@ theorem range_eq_range' {n : Nat} : range n = range' 0 n :=
theorem getElem?_range {i n : Nat} (h : i < n) : (range n)[i]? = some i := by
simp [range_eq_range', getElem?_range' h]
@[simp, grind =] theorem getElem_range (h : j < (range n).length) : (range n)[j] = j := by
@[simp] theorem getElem_range (h : j < (range n).length) : (range n)[j] = j := by
simp [range_eq_range']
theorem range_succ_eq_map {n : Nat} : range (n + 1) = 0 :: map succ (range n) := by
@@ -154,23 +162,23 @@ theorem range_succ_eq_map {n : Nat} : range (n + 1) = 0 :: map succ (range n) :=
theorem range'_eq_map_range {s n : Nat} : range' s n = map (s + ·) (range n) := by
rw [range_eq_range', map_add_range']; rfl
@[simp, grind =] theorem length_range {n : Nat} : (range n).length = n := by
@[simp] theorem length_range {n : Nat} : (range n).length = n := by
simp only [range_eq_range', length_range']
@[simp, grind =] theorem range_eq_nil {n : Nat} : range n = [] n = 0 := by
@[simp] theorem range_eq_nil {n : Nat} : range n = [] n = 0 := by
rw [ length_eq_zero_iff, length_range]
theorem range_ne_nil {n : Nat} : range n [] n 0 := by
cases n <;> simp
@[simp, grind =] theorem tail_range : (range n).tail = range' 1 (n - 1) := by
@[simp] theorem tail_range : (range n).tail = range' 1 (n - 1) := by
rw [range_eq_range', tail_range']
@[simp, grind =]
@[simp]
theorem range_sublist {m n : Nat} : range m <+ range n m n := by
simp only [range_eq_range', range'_sublist_right]
@[simp, grind =]
@[simp]
theorem range_subset {m n : Nat} : range m range n m n := by
simp only [range_eq_range', range'_subset_right, lt_succ_self]
@@ -188,7 +196,7 @@ theorem head?_range {n : Nat} : (range n).head? = if n = 0 then none else some 0
simp only [range_succ, head?_append, ih]
split <;> simp_all
@[simp, grind =] theorem head_range {n : Nat} (h) : (range n).head h = 0 := by
@[simp] theorem head_range {n : Nat} (h) : (range n).head h = 0 := by
cases n with
| zero => simp at h
| succ n => simp [head?_range, head_eq_iff_head?_eq_some]
@@ -200,7 +208,7 @@ theorem getLast?_range {n : Nat} : (range n).getLast? = if n = 0 then none else
simp only [range_succ, getLast?_append, ih]
split <;> simp_all
@[simp, grind =] theorem getLast_range {n : Nat} (h) : (range n).getLast h = n - 1 := by
@[simp] theorem getLast_range {n : Nat} (h) : (range n).getLast h = n - 1 := by
cases n with
| zero => simp at h
| succ n => simp [getLast?_range, getLast_eq_iff_getLast?_eq_some]

View File

@@ -68,9 +68,9 @@ theorem take_of_length_le {l : List α} (h : l.length ≤ i) : take i l = l := b
theorem lt_length_of_take_ne_self {l : List α} {i} (h : l.take i l) : i < l.length :=
gt_of_not_le (mt take_of_length_le h)
@[simp, grind =] theorem drop_length {l : List α} : l.drop l.length = [] := drop_of_length_le (Nat.le_refl _)
@[simp] theorem drop_length {l : List α} : l.drop l.length = [] := drop_of_length_le (Nat.le_refl _)
@[simp, grind =] theorem take_length {l : List α} : l.take l.length = l := take_of_length_le (Nat.le_refl _)
@[simp] theorem take_length {l : List α} : l.take l.length = l := take_of_length_le (Nat.le_refl _)
@[simp]
theorem getElem_cons_drop : {l : List α} {i : Nat} (h : i < l.length),

View File

@@ -11,7 +11,6 @@ public import Init.Data.Nat.Div
public import Init.Data.Nat.Dvd
public import Init.Data.Nat.Gcd
public import Init.Data.Nat.MinMax
public import Init.Data.Nat.Order
public import Init.Data.Nat.Bitwise
public import Init.Data.Nat.Control
public import Init.Data.Nat.Log2
@@ -24,6 +23,5 @@ public import Init.Data.Nat.Lcm
public import Init.Data.Nat.Compare
public import Init.Data.Nat.Simproc
public import Init.Data.Nat.Fold
public import Init.Data.Nat.Order
public section

View File

@@ -1,41 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Nat.Basic
import Init.Data.Nat.MinMax
public import Init.Data.Order.Factories
open Std
namespace Nat
public instance instIsLinearOrder : IsLinearOrder Nat := by
apply IsLinearOrder.of_le
· constructor; apply Nat.le_antisymm
· constructor; apply Nat.le_trans
· constructor; apply Nat.le_total
public instance : LawfulOrderLT Nat := by
apply LawfulOrderLT.of_le
simp [Nat.lt_iff_le_and_ne]
public instance : LawfulOrderMin Nat := by
apply LawfulOrderMin.of_le
· apply Nat.le_min
· intro a b
simp only [Nat.min_def]
split <;> simp
public instance : LawfulOrderMax Nat := by
apply LawfulOrderMax.of_le
· apply Nat.max_le
· intro a b
simp only [Nat.max_def]
split <;> simp
end Nat

View File

@@ -58,9 +58,9 @@ theorem getD_of_ne_none {x : Option α} (hx : x ≠ none) (y : α) : some (x.get
theorem getD_eq_iff {o : Option α} {a b} : o.getD a = b (o = some b o = none a = b) := by
cases o <;> simp
@[simp, grind =] theorem get!_none [Inhabited α] : (none : Option α).get! = default := rfl
@[simp, grind] theorem get!_none [Inhabited α] : (none : Option α).get! = default := rfl
@[simp, grind =] theorem get!_some [Inhabited α] {a : α} : (some a).get! = a := rfl
@[simp, grind] theorem get!_some [Inhabited α] {a : α} : (some a).get! = a := rfl
theorem get_eq_get! [Inhabited α] : (o : Option α) {h : o.isSome} o.get h = o.get!
| some _, _ => rfl
@@ -120,7 +120,7 @@ theorem isSome_of_eq_some {x : Option α} {y : α} (h : x = some y) : x.isSome :
@[simp] theorem isNone_eq_false_iff : isNone a = false a.isSome = true := by
cases a <;> simp
@[simp, grind =]
@[simp, grind]
theorem not_isSome (a : Option α) : (!a.isSome) = a.isNone := by
cases a <;> simp
@@ -129,7 +129,7 @@ theorem not_comp_isSome : (! ·) ∘ @Option.isSome α = Option.isNone := by
funext
simp
@[simp, grind =]
@[simp, grind]
theorem not_isNone (a : Option α) : (!a.isNone) = a.isSome := by
cases a <;> simp
@@ -191,15 +191,11 @@ theorem forall_ne_none {p : Option α → Prop} : (∀ x (_ : x ≠ none), p x)
@[deprecated forall_ne_none (since := "2025-04-04")]
abbrev ball_ne_none := @forall_ne_none
@[simp] theorem pure_def : pure = @some α := rfl
@[simp, grind] theorem pure_def : pure = @some α := rfl
@[grind =] theorem pure_apply : pure x = some x := rfl
@[simp, grind] theorem bind_eq_bind : bind = @Option.bind α β := rfl
@[simp] theorem bind_eq_bind : bind = @Option.bind α β := rfl
@[grind =] theorem bind_apply : bind x f = Option.bind x f := rfl
@[simp, grind =] theorem bind_fun_some (x : Option α) : x.bind some = x := by cases x <;> rfl
@[simp, grind] theorem bind_fun_some (x : Option α) : x.bind some = x := by cases x <;> rfl
@[simp] theorem bind_fun_none (x : Option α) : x.bind (fun _ => none (α := β)) = none := by
cases x <;> rfl
@@ -220,7 +216,7 @@ theorem bind_eq_none' {o : Option α} {f : α → Option β} :
o.bind f = none b a, o = some a f a some b := by
cases o <;> simp [eq_none_iff_forall_ne_some]
@[grind =] theorem mem_bind_iff {o : Option α} {f : α Option β} :
@[grind] theorem mem_bind_iff {o : Option α} {f : α Option β} :
b o.bind f a, a o b f a := by
cases o <;> simp
@@ -228,7 +224,7 @@ theorem bind_comm {f : α → β → Option γ} (a : Option α) (b : Option β)
(a.bind fun x => b.bind (f x)) = b.bind fun y => a.bind fun x => f x y := by
cases a <;> cases b <;> rfl
@[grind =]
@[grind]
theorem bind_assoc (x : Option α) (f : α Option β) (g : β Option γ) :
(x.bind f).bind g = x.bind fun y => (f y).bind g := by cases x <;> rfl
@@ -236,12 +232,12 @@ theorem bind_congr {α β} {o : Option α} {f g : α → Option β} :
(h : a, o = some a f a = g a) o.bind f = o.bind g := by
cases o <;> simp
@[grind =]
@[grind]
theorem isSome_bind {α β : Type _} (x : Option α) (f : α Option β) :
(x.bind f).isSome = x.any (fun x => (f x).isSome) := by
cases x <;> rfl
@[grind =]
@[grind]
theorem isNone_bind {α β : Type _} (x : Option α) (f : α Option β) :
(x.bind f).isNone = x.all (fun x => (f x).isNone) := by
cases x <;> rfl
@@ -254,7 +250,7 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α
(h : (x.bind f).isSome) : (f (x.get (isSome_of_isSome_bind h))).isSome := by
cases x <;> trivial
@[simp, grind =] theorem get_bind {α β : Type _} {x : Option α} {f : α Option β} (h : (x.bind f).isSome) :
@[simp, grind] theorem get_bind {α β : Type _} {x : Option α} {f : α Option β} (h : (x.bind f).isSome) :
(x.bind f).get h = (f (x.get (isSome_of_isSome_bind h))).get
(isSome_apply_of_isSome_bind h) := by
cases x <;> trivial
@@ -267,7 +263,7 @@ theorem isSome_apply_of_isSome_bind {α β : Type _} {x : Option α} {f : α
(o.bind f).all p = o.all (Option.all p f) := by
cases o <;> simp
@[grind =] theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
@[grind] theorem bind_id_eq_join {x : Option (Option α)} : x.bind id = x.join := rfl
theorem join_eq_some_iff : x.join = some a x = some (some a) := by
simp [ bind_id_eq_join, bind_eq_some_iff]
@@ -291,9 +287,7 @@ theorem bind_join {f : α → Option β} {o : Option (Option α)} :
o.join.bind f = o.bind (·.bind f) := by
cases o <;> simp
@[simp] theorem map_eq_map : Functor.map f = Option.map f := rfl
@[grind =] theorem map_apply : Functor.map f x = Option.map f x := rfl
@[simp, grind] theorem map_eq_map : Functor.map f = Option.map f := rfl
@[deprecated map_none (since := "2025-04-10")]
abbrev map_none' := @map_none
@@ -319,13 +313,13 @@ abbrev map_eq_none := @map_eq_none_iff
@[deprecated map_eq_none_iff (since := "2025-04-10")]
abbrev map_eq_none' := @map_eq_none_iff
@[simp, grind =] theorem isSome_map {x : Option α} : (x.map f).isSome = x.isSome := by
@[simp, grind] theorem isSome_map {x : Option α} : (x.map f).isSome = x.isSome := by
cases x <;> simp
@[deprecated isSome_map (since := "2025-04-10")]
abbrev isSome_map' := @isSome_map
@[simp, grind =] theorem isNone_map {x : Option α} : (x.map f).isNone = x.isNone := by
@[simp, grind] theorem isNone_map {x : Option α} : (x.map f).isNone = x.isNone := by
cases x <;> simp
theorem map_eq_bind {x : Option α} : x.map f = x.bind (some f) := by
@@ -335,32 +329,28 @@ theorem map_congr {x : Option α} (h : ∀ a, x = some a → f a = g a) :
x.map f = x.map g := by
cases x <;> simp only [map_none, map_some, h]
@[simp] theorem map_id_fun {α : Type u} : Option.map (id : α α) = id := by
@[simp, grind] theorem map_id_fun {α : Type u} : Option.map (id : α α) = id := by
funext; simp [map_id]
@[grind =] theorem map_id_apply {α : Type u} {x : Option α} : Option.map (id : α α) x = x := by simp
theorem map_id' {x : Option α} : (x.map fun a => a) = x := congrFun map_id x
@[simp] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
@[simp, grind] theorem map_id_fun' {α : Type u} : Option.map (fun (a : α) => a) = id := by
funext; simp [map_id']
@[grind =] theorem map_id_apply' {α : Type u} {x : Option α} : Option.map (fun (a : α) => a) x = x := by simp
@[simp, grind =] theorem get_map {f : α β} {o : Option α} {h : (o.map f).isSome} :
@[simp, grind] theorem get_map {f : α β} {o : Option α} {h : (o.map f).isSome} :
(o.map f).get h = f (o.get (by simpa using h)) := by
cases o with
| none => simp at h
| some a => simp
@[simp] theorem map_map (h : β γ) (g : α β) (x : Option α) :
@[simp, grind _=_] theorem map_map (h : β γ) (g : α β) (x : Option α) :
(x.map g).map h = x.map (h g) := by
cases x <;> simp only [map_none, map_some, ··]
theorem comp_map (h : β γ) (g : α β) (x : Option α) : x.map (h g) = (x.map g).map h :=
(map_map ..).symm
@[simp] theorem map_comp_map (f : α β) (g : β γ) :
@[simp, grind _=_] theorem map_comp_map (f : α β) (g : β γ) :
Option.map g Option.map f = Option.map (g f) := by funext x; simp
theorem mem_map_of_mem (g : α β) (h : a x) : g a Option.map g x := h.symm map_some ..
@@ -382,9 +372,9 @@ theorem map_inj_right {f : α → β} {o o' : Option α} (w : ∀ x y, f x = f y
(if h : c then some (a h) else none).map f = if h : c then some (f (a h)) else none := by
split <;> rfl
@[simp, grind =] theorem filter_none (p : α Bool) : none.filter p = none := rfl
@[simp, grind] theorem filter_none (p : α Bool) : none.filter p = none := rfl
@[grind =] theorem filter_some : Option.filter p (some a) = if p a then some a else none := rfl
@[grind] theorem filter_some : Option.filter p (some a) = if p a then some a else none := rfl
theorem filter_some_pos (h : p a) : Option.filter p (some a) = some a := by
rw [filter_some, if_pos h]
@@ -427,12 +417,12 @@ theorem filter_some_eq_some : Option.filter p (some a) = some a ↔ p a := by si
theorem filter_some_eq_none : Option.filter p (some a) = none ¬p a := by simp
@[grind =]
@[grind]
theorem mem_filter_iff {p : α Bool} {a : α} {o : Option α} :
a o.filter p a o p a := by
simp
@[grind =]
@[grind]
theorem bind_guard (x : Option α) (p : α Bool) :
x.bind (Option.guard p) = x.filter p := by
cases x <;> rfl
@@ -467,7 +457,7 @@ theorem filter_eq_bind (x : Option α) (p : α → Bool) :
| false => by simp [filter_some_neg h, h]
| true => by simp [filter_some_pos h, h]
@[simp, grind =] theorem isSome_filter : Option.isSome (Option.filter p o) = Option.any p o :=
@[simp, grind] theorem isSome_filter : Option.isSome (Option.filter p o) = Option.any p o :=
match o with
| none => rfl
| some a =>
@@ -546,12 +536,12 @@ theorem get_of_any_eq_true (p : α → Bool) (x : Option α) (h : x.any p = true
p (x.get (isSome_of_any h)) :=
any_eq_true_iff_get p x |>.1 h |>.2
@[grind =]
@[grind]
theorem any_map {α β : Type _} {x : Option α} {f : α β} {p : β Bool} :
(x.map f).any p = x.any (fun a => p (f a)) := by
cases x <;> rfl
@[grind =]
@[grind]
theorem all_map {α β : Type _} {x : Option α} {f : α β} {p : β Bool} :
(x.map f).all p = x.all (fun a => p (f a)) := by
cases x <;> rfl
@@ -559,13 +549,13 @@ theorem all_map {α β : Type _} {x : Option α} {f : α → β} {p : β → Boo
theorem bind_map_comm {α β} {x : Option (Option α)} {f : α β} :
x.bind (Option.map f) = (x.map (Option.map f)).bind id := by cases x <;> simp
@[grind =] theorem bind_map {f : α β} {g : β Option γ} {x : Option α} :
@[grind] theorem bind_map {f : α β} {g : β Option γ} {x : Option α} :
(x.map f).bind g = x.bind (g f) := by cases x <;> simp
@[simp, grind =] theorem map_bind {f : α Option β} {g : β γ} {x : Option α} :
@[simp, grind] theorem map_bind {f : α Option β} {g : β γ} {x : Option α} :
(x.bind f).map g = x.bind (Option.map g f) := by cases x <;> simp
@[grind =] theorem join_map_eq_map_join {f : α β} {x : Option (Option α)} :
@[grind] theorem join_map_eq_map_join {f : α β} {x : Option (Option α)} :
(x.map (Option.map f)).join = x.join.map f := by cases x <;> simp
@[grind _=_] theorem join_join {x : Option (Option (Option α))} : x.join.join = (x.map join).join := by
@@ -662,11 +652,10 @@ theorem get_none_eq_iff_true {h} : (none : Option α).get h = a ↔ True := by
simp only [guard]
split <;> simp
@[grind]
theorem guard_def (p : α Bool) :
Option.guard p = fun x => if p x then some x else none := rfl
@[grind =] theorem guard_apply : Option.guard p x = if p x then some x else none := rfl
@[deprecated guard_def (since := "2025-05-15")]
theorem guard_eq_map (p : α Bool) :
Option.guard p = fun x => Option.map (fun _ => x) (if p x then some x else none) := by
@@ -715,13 +704,13 @@ theorem merge_eq_or_eq {f : ααα} (h : ∀ a b, f a b = a f a b
| none, some _ => .inr rfl
| some a, some b => by have := h a b; simp [merge] at this ; exact this
@[simp, grind =] theorem merge_none_left {f} {b : Option α} : merge f none b = b := by
@[simp, grind] theorem merge_none_left {f} {b : Option α} : merge f none b = b := by
cases b <;> rfl
@[simp, grind =] theorem merge_none_right {f} {a : Option α} : merge f a none = a := by
@[simp, grind] theorem merge_none_right {f} {a : Option α} : merge f a none = a := by
cases a <;> rfl
@[simp, grind =] theorem merge_some_some {f} {a b : α} :
@[simp, grind] theorem merge_some_some {f} {a b : α} :
merge f (some a) (some b) = some (f a b) := rfl
@[deprecated merge_eq_or_eq (since := "2025-04-04")]
@@ -795,9 +784,9 @@ theorem get_merge {o o' : Option α} {f : ααα} {i : α} [Std.Lawful
(o.merge f o').get h = f (o.getD i) (o'.getD i) := by
cases o <;> cases o' <;> simp [Std.LawfulLeftIdentity.left_id, Std.LawfulRightIdentity.right_id]
@[simp, grind =] theorem elim_none (x : β) (f : α β) : none.elim x f = x := rfl
@[simp, grind] theorem elim_none (x : β) (f : α β) : none.elim x f = x := rfl
@[simp, grind =] theorem elim_some (x : β) (f : α β) (a : α) : (some a).elim x f = f a := rfl
@[simp, grind] theorem elim_some (x : β) (f : α β) (a : α) : (some a).elim x f = f a := rfl
@[grind =] theorem elim_filter {o : Option α} {b : β} :
Option.elim (Option.filter p o) b f = Option.elim o b (fun a => if p a then f a else b) :=
@@ -815,8 +804,7 @@ theorem get_merge {o o' : Option α} {f : ααα} {i : α} [Std.Lawful
theorem elim_guard : (guard p a).elim b f = if p a then f a else b := by
cases h : p a <;> simp [*, guard]
-- I don't see how to construct a good grind pattern to instantiate this.
@[simp] theorem getD_map (f : α β) (x : α) (o : Option α) :
@[simp, grind] theorem getD_map (f : α β) (x : α) (o : Option α) :
(o.map f).getD (f x) = f (getD o x) := by cases o <;> rfl
section choice
@@ -879,37 +867,37 @@ theorem get!_choice [Inhabited α] : (choice α).get! = (choice α).get isSome_c
end choice
@[simp, grind =] theorem toList_some (a : α) : (some a).toList = [a] := rfl
@[simp, grind =] theorem toList_none (α : Type _) : (none : Option α).toList = [] := rfl
@[simp, grind] theorem toList_some (a : α) : (some a).toList = [a] := rfl
@[simp, grind] theorem toList_none (α : Type _) : (none : Option α).toList = [] := rfl
@[simp, grind =] theorem toArray_some (a : α) : (some a).toArray = #[a] := rfl
@[simp, grind =] theorem toArray_none (α : Type _) : (none : Option α).toArray = #[] := rfl
@[simp, grind] theorem toArray_some (a : α) : (some a).toArray = #[a] := rfl
@[simp, grind] theorem toArray_none (α : Type _) : (none : Option α).toArray = #[] := rfl
-- See `Init.Data.Option.List` for lemmas about `toList`.
@[simp, grind =] theorem some_or : (some a).or o = some a := rfl
@[simp, grind =] theorem none_or : none.or o = o := rfl
@[simp, grind] theorem some_or : (some a).or o = some a := rfl
@[simp, grind] theorem none_or : none.or o = o := rfl
theorem or_eq_right_of_none {o o' : Option α} (h : o = none) : o.or o' = o' := by
cases h; simp
@[simp, grind =] theorem or_some {o : Option α} : o.or (some a) = some (o.getD a) := by
@[simp, grind] theorem or_some {o : Option α} : o.or (some a) = some (o.getD a) := by
cases o <;> rfl
@[deprecated or_some (since := "2025-05-03")]
abbrev or_some' := @or_some
@[simp, grind =]
@[simp, grind]
theorem or_none : or o none = o := by
cases o <;> rfl
theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
cases o <;> rfl
@[simp, grind =] theorem isSome_or : (or o o').isSome = (o.isSome || o'.isSome) := by
@[simp, grind] theorem isSome_or : (or o o').isSome = (o.isSome || o'.isSome) := by
cases o <;> rfl
@[simp, grind =] theorem isNone_or : (or o o').isNone = (o.isNone && o'.isNone) := by
@[simp, grind] theorem isNone_or : (or o o').isNone = (o.isNone && o'.isNone) := by
cases o <;> rfl
@[simp] theorem or_eq_none_iff : or o o' = none o = none o' = none := by
@@ -924,7 +912,7 @@ abbrev or_eq_none := @or_eq_none_iff
@[deprecated or_eq_some_iff (since := "2025-04-10")]
abbrev or_eq_some := @or_eq_some_iff
@[grind _=_] theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
@[grind] theorem or_assoc : or (or o₁ o₂) o₃ = or o₁ (or o₂ o₃) := by
cases o₁ <;> cases o₂ <;> rfl
instance : Std.Associative (or (α := α)) := @or_assoc _
@@ -935,7 +923,7 @@ instance : Std.LawfulIdentity (or (α := α)) none where
left_id := @none_or _
right_id := @or_none _
@[simp, grind =]
@[simp, grind]
theorem or_self : or o o = o := by
cases o <;> rfl
instance : Std.IdempotentOp (or (α := α)) := @or_self _
@@ -974,15 +962,13 @@ theorem guard_or_guard : (guard p a).or (guard q a) = guard (fun x => p x || q x
/-! ### `orElse` -/
/-- The `simp` normal form of `o <|> o'` is `o.or o'` via `orElse_eq_orElse` and `orElse_eq_or`. -/
@[simp] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
@[grind =] theorem orElse_apply : HOrElse.hOrElse o o' = Option.orElse o o' := rfl
@[simp, grind] theorem orElse_eq_orElse : HOrElse.hOrElse = @Option.orElse α := rfl
theorem or_eq_orElse : or o o' = o.orElse (fun _ => o') := by
cases o <;> rfl
/-- The `simp` normal form of `o.orElse f` is o.or (f ())`. -/
@[simp, grind =] theorem orElse_eq_or {o : Option α} {f} : o.orElse f = o.or (f ()) := by
@[simp, grind] theorem orElse_eq_or {o : Option α} {f} : o.orElse f = o.or (f ()) := by
simp [or_eq_orElse]
@[deprecated or_some (since := "2025-05-03")]
@@ -1015,13 +1001,13 @@ section beq
variable [BEq α]
@[simp, grind =] theorem none_beq_none : ((none : Option α) == none) = true := rfl
@[simp, grind =] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
@[simp, grind =] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
@[simp, grind =] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
@[simp, grind] theorem none_beq_none : ((none : Option α) == none) = true := rfl
@[simp, grind] theorem none_beq_some (a : α) : ((none : Option α) == some a) = false := rfl
@[simp, grind] theorem some_beq_none (a : α) : ((some a : Option α) == none) = false := rfl
@[simp, grind] theorem some_beq_some {a b : α} : (some a == some b) = (a == b) := rfl
/-- We simplify away `isEqSome` in terms of `==`. -/
@[simp, grind =] theorem isEqSome_eq_beq_some {o : Option α} : isEqSome o y = (o == some y) := by
@[simp, grind] theorem isEqSome_eq_beq_some {o : Option α} : isEqSome o y = (o == some y) := by
cases o <;> simp [isEqSome]
@[simp] theorem reflBEq_iff : ReflBEq (Option α) ReflBEq α := by
@@ -1142,15 +1128,12 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
@[simp] theorem isSome_dite {p : Prop} {_ : Decidable p} {b : p β} :
(if h : p then some (b h) else none).isSome = true p := by
split <;> simpa
@[simp] theorem isSome_ite {p : Prop} {_ : Decidable p} :
(if p then some b else none).isSome = true p := by
split <;> simpa
@[simp] theorem isSome_dite' {p : Prop} {_ : Decidable p} {b : ¬ p β} :
(if h : p then none else some (b h)).isSome = true ¬ p := by
split <;> simpa
@[simp] theorem isSome_ite' {p : Prop} {_ : Decidable p} :
(if p then none else some b).isSome = true ¬ p := by
split <;> simpa
@@ -1162,11 +1145,9 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
· exfalso
simp at w
contradiction
@[simp] theorem get_ite {p : Prop} {_ : Decidable p} (h) :
(if p then some b else none).get h = b := by
simpa using get_dite (p := p) (fun _ => b) (by simpa using h)
@[simp] theorem get_dite' {p : Prop} {_ : Decidable p} (b : ¬ p β) (w) :
(if h : p then none else some (b h)).get w = b (by simpa using w) := by
split
@@ -1174,14 +1155,13 @@ theorem mem_ite_none_right {x : α} {_ : Decidable p} {l : Option α} :
simp at w
contradiction
· simp
@[simp] theorem get_ite' {p : Prop} {_ : Decidable p} (h) :
(if p then none else some b).get h = b := by
simpa using get_dite' (p := p) (fun _ => b) (by simpa using h)
end ite
@[simp, grind =] theorem get_filter {α : Type _} {x : Option α} {f : α Bool} (h : (x.filter f).isSome) :
@[simp, grind] theorem get_filter {α : Type _} {x : Option α} {f : α Bool} (h : (x.filter f).isSome) :
(x.filter f).get h = x.get (isSome_of_isSome_filter f x h) := by
cases x
· contradiction
@@ -1196,16 +1176,16 @@ end ite
@[grind = gen] theorem pbind_none' (h : x = none) : pbind x f = none := by subst h; rfl
@[grind = gen] theorem pbind_some' (h : x = some a) : pbind x f = f a h := by subst h; rfl
@[simp, grind =] theorem map_pbind {o : Option α} {f : (a : α) o = some a Option β}
@[simp, grind] theorem map_pbind {o : Option α} {f : (a : α) o = some a Option β}
{g : β γ} : (o.pbind f).map g = o.pbind (fun a h => (f a h).map g) := by
cases o <;> rfl
@[simp, grind =] theorem pbind_map {α β γ : Type _} (o : Option α)
@[simp, grind] theorem pbind_map {α β γ : Type _} (o : Option α)
(f : α β) (g : (x : β) o.map f = some x Option γ) :
(o.map f).pbind g = o.pbind (fun x h => g (f x) (h rfl)) := by
cases o <;> rfl
@[simp] theorem pbind_eq_bind {α β : Type _} (o : Option α)
@[simp, grind] theorem pbind_eq_bind {α β : Type _} (o : Option α)
(f : α Option β) : o.pbind (fun x _ => f x) = o.bind f := by
cases o <;> rfl
@@ -1273,11 +1253,11 @@ theorem get_pbind {o : Option α} {f : (a : α) → o = some a → Option β} {h
pmap f o h = none o = none := by
cases o <;> simp
@[simp, grind =] theorem isSome_pmap {p : α Prop} {f : (a : α), p a β} {o : Option α} {h} :
@[simp, grind] theorem isSome_pmap {p : α Prop} {f : (a : α), p a β} {o : Option α} {h} :
(pmap f o h).isSome = o.isSome := by
cases o <;> simp
@[simp, grind =] theorem isNone_pmap {p : α Prop} {f : (a : α), p a β} {o : Option α} {h} :
@[simp, grind] theorem isNone_pmap {p : α Prop} {f : (a : α), p a β} {o : Option α} {h} :
(pmap f o h).isNone = o.isNone := by
cases o <;> simp
@@ -1299,11 +1279,11 @@ theorem pmap_eq_map (p : α → Prop) (f : α → β) (o : Option α) (H) :
@pmap _ _ p (fun a _ => f a) o H = Option.map f o := by
cases o <;> simp
@[grind =] theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (o H) :
@[grind] theorem map_pmap {p : α Prop} (g : β γ) (f : a, p a β) (o H) :
Option.map g (pmap f o H) = pmap (fun a h => g (f a h)) o H := by
cases o <;> simp
@[grind =] theorem pmap_map (o : Option α) (f : α β) {p : β Prop} (g : b, p b γ) (H) :
@[grind] theorem pmap_map (o : Option α) (f : α β) {p : β Prop} (g : b, p b γ) (H) :
pmap g (o.map f) H =
pmap (fun a h => g (f a) h) o (fun a m => H (f a) (map_eq_some_iff.2 _, m, rfl)) := by
cases o <;> simp
@@ -1360,7 +1340,7 @@ theorem get_pmap {p : α → Bool} {f : (x : α) → p x → β} {o : Option α}
@[simp] theorem pelim_eq_elim : pelim o b (fun a _ => f a) = o.elim b f := by
cases o <;> simp
@[simp, grind =] theorem elim_pmap {p : α Prop} (f : (a : α) p a β) (o : Option α)
@[simp, grind] theorem elim_pmap {p : α Prop} (f : (a : α) p a β) (o : Option α)
(H : (a : α), o = some a p a) (g : γ) (g' : β γ) :
(o.pmap f H).elim g g' =
o.pelim g (fun a h => g' (f a (H a h))) := by
@@ -1407,11 +1387,11 @@ theorem pfilter_congr {α : Type u} {o o' : Option α} (ho : o = o')
congr; funext a ha
exact hf a ha
@[simp, grind =] theorem pfilter_none {α : Type _} {p : (a : α) none = some a Bool} :
@[simp, grind] theorem pfilter_none {α : Type _} {p : (a : α) none = some a Bool} :
none.pfilter p = none := by
rfl
@[simp, grind =] theorem pfilter_some {α : Type _} {x : α} {p : (a : α) some x = some a Bool} :
@[simp, grind] theorem pfilter_some {α : Type _} {x : α} {p : (a : α) some x = some a Bool} :
(some x).pfilter p = if p x rfl then some x else none := by
simp only [pfilter, cond_eq_if]
@@ -1436,7 +1416,7 @@ theorem isNone_pfilter_iff {o : Option α} {p : (a : α) → o = some a → Bool
Bool.not_eq_true, some.injEq]
exact fun h _ h' => h' h, fun h => h _ rfl
@[simp, grind =] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) o = some a Bool}
@[simp, grind] theorem get_pfilter {α : Type _} {o : Option α} {p : (a : α) o = some a Bool}
(h : (o.pfilter p).isSome) :
(o.pfilter p).get h = o.get (isSome_of_isSome_pfilter h) := by
cases o <;> simp

View File

@@ -1,12 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Order.Classes
public import Init.Data.Order.Lemmas
public import Init.Data.Order.Factories
public import Init.Data.Subtype.Order

View File

@@ -1,173 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Core
namespace Std
/-!
# Order-related typeclasses
This module provides the typeclasses used to state that basic operations on some type `α`
reflect a certain well-behaved order structure on `α`.
The basic operations are provided by the typeclasses `LE α`, `LT α`, `BEq α`, `Ord α`, `Min α` and
`Max α`.
All of them describe at least some way to compare elements in `α`. Usually, any subset of them
is available and one can/must show that these comparisons are well-behaved in some sense.
For example, one could merely require that the available operations reflect a preorder
(where the less-or-equal relation only needs to be reflexive and transitive). Alternatively,
one could require a full linear order (additionally requiring antisymmetry and totality of the
less-or-equal relation).
There are many ways to characterize, say, linear orders:
* `(· ≤ ·)` is reflexive, transitive, antisymmetric and total.
* `(· ≤ ·)` is antisymmetric, `a < b ↔ ¬ b ≤ a` and `(· < ·)` is irreflexive, transitive and asymmetric.
* `min a b` is either `a` or `b`, is symmetric and satisfies the
following property: `min c (min a b) = c` if and only if `min c a = c` and `min c b = c`.
It is desirable that lemmas about linear orders state this hypothesis in a canonical way.
Therefore, the classes defining preorders, partial orders, linear preorders and linear orders
are all formulated purely in terms of `LE`. For other operations, there are
classes for compatibility of `LE` with other operations. Hence, a lemma may look like:
```lean
theorem lt_trans {α : Type u} [LE α] [LT α]
[IsPreorder α] -- The order on `α` induced by `LE α` is, among other things, transitive.
[LawfulOrderLT α] -- `<` is the less-than relation induced by `LE α`.
{a b : α} : a < b → b < c → a < c := by
sorry
```
-/
/--
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
is a preorder. In other words, the less-or-equal relation is reflexive and transitive.
-/
public class IsPreorder (α : Type u) [LE α] where
le_refl : a : α, a a
le_trans : a b c : α, a b b c a c
/--
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
is a partial order.
In other words, the less-or-equal relation is reflexive, transitive and antisymmetric.
-/
public class IsPartialOrder (α : Type u) [LE α] extends IsPreorder α where
le_antisymm : a b : α, a b b a a = b
/--
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
is a linear preorder.
In other words, the less-or-equal relation is reflexive, transitive and total.
-/
public class IsLinearPreorder (α : Type u) [LE α] extends IsPreorder α where
le_total : a b : α, a b b a
/--
This typeclass states that the order structure on `α`, represented by an `LE α` instance,
is a linear order.
In other words, the less-or-equal relation is reflexive, transitive, antisymmetric and total.
-/
public class IsLinearOrder (α : Type u) [LE α] extends IsPartialOrder α, IsLinearPreorder α
section LT
/--
This typeclass states that the synthesized `LT α` instance is compatible with the `LE α`
instance. This means that `LT.lt a b` holds if and only if `a` is less or equal to `b` according
to the `LE α` instance, but `b` is not less or equal to `a`.
`LawfulOrderLT α` automatically entails that `LT α` is asymmetric: `a < b` and `b < a` can never
be true simultaneously.
`LT α` does not uniquely determine the `LE α`: There can be only one compatible order data
instance that is total, but there can be others that are not total.
-/
public class LawfulOrderLT (α : Type u) [LT α] [LE α] where
lt_iff : a b : α, a < b a b ¬ b a
end LT
section Min
/--
This typeclass states that `Min.min a b` returns one of its arguments, either `a` or `b`.
-/
public class MinEqOr (α : Type u) [Min α] where
min_eq_or : a b : α, min a b = a min a b = b
/--
If both `a` and `b` satisfy some property `P`, then so does `min a b`, because it is equal to
either `a` or `b`.
-/
public def MinEqOr.elim {α : Type u} [Min α] [MinEqOr α] {P : α Prop} {a b : α} (ha : P a) (hb : P b) :
P (min a b) := by
cases MinEqOr.min_eq_or a b <;> rename_i h
case inl => exact h.symm ha
case inr => exact h.symm hb
/--
This typeclass states that being less or equal to `min a b` is equivalent to being less or
equal to both `a` and `b`..
-/
public class LawfulOrderInf (α : Type u) [Min α] [LE α] where
le_min_iff : a b c : α, a (min b c) a b a c
/--
This typeclass bundles `MinEqOr α` and `LawfulOrderInf α`. It characterizes when a `Min α`
instance reasonably computes minima in some type `α` that has an `LE α` instance.
As long as `α` is a preorder (see `IsPreorder α`), this typeclass implies that the order on
`α` is total and that `Min.min a b` returns either `a` or `b`, whichever is less or equal to
the other.
-/
public class LawfulOrderMin (α : Type u) [Min α] [LE α] extends MinEqOr α, LawfulOrderInf α
end Min
section Max
/--
This typeclass states that `Max.max a b` returns one of its arguments, either `a` or `b`.
-/
public class MaxEqOr (α : Type u) [Max α] where
max_eq_or : a b : α, max a b = a max a b = b
/--
If both `a` and `b` satisfy some property `P`, then so does `max a b`, because it is equal to
either `a` or `b`.
-/
public def MaxEqOr.elim {α : Type u} [Max α] [MaxEqOr α] {P : α Prop} {a b : α} (ha : P a) (hb : P b) :
P (max a b) := by
cases MaxEqOr.max_eq_or a b <;> rename_i h
case inl => exact h.symm ha
case inr => exact h.symm hb
/--
This typeclass states that being less or equal to `Max.max a b` is equivalent to being less or
equal to both `a` and `b`.
-/
public class LawfulOrderSup (α : Type u) [Max α] [LE α] where
max_le_iff : a b c : α, (max a b) c a c b c
/--
This typeclass bundles `MaxEqOr α` and `LawfulOrderSup α`. It characterizes when a `Max α`
instance reasonably computes maxima in some type `α` that has an `LE α` instance.
As long as `α` is a preorder (see `IsPreorder α`), this typeclass implies that the order on
`α` is total and that `Min.min a b` returns either `a` or `b`, whichever is greater or equal to
the other.
-/
public class LawfulOrderMax (α : Type u) [Max α] [LE α] extends MaxEqOr α, LawfulOrderSup α
end Max
end Std

View File

@@ -1,236 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Order.Classes
import Init.Classical
namespace Std
/-!
This module provides utilities for the creation of order-related typeclass instances.
-/
section OfLE
/--
This instance is only publicly defined in `Init.Data.Order.Lemmas`.
-/
instance {r : α α Prop} [Total r] : Refl r where
refl a := by simpa using Total.total a a
/--
If an `LE α` instance is reflexive and transitive, then it represents a preorder.
-/
public theorem IsPreorder.of_le {α : Type u} [LE α]
(le_refl : Std.Refl (α := α) (· ·) := by exact inferInstance)
(le_trans : Trans (α := α) (· ·) (· ·) (· ·) := by exact inferInstance) :
IsPreorder α where
le_refl := le_refl.refl
le_trans _ _ _ := le_trans.trans
/--
If an `LE α` instance is transitive and total, then it represents a linear preorder.
-/
public theorem IsLinearPreorder.of_le {α : Type u} [LE α]
(le_trans : Trans (α := α) (· ·) (· ·) (· ·) := by exact inferInstance)
(le_total : Total (α := α) (· ·) := by exact inferInstance) :
IsLinearPreorder α where
toIsPreorder := .of_le
le_total := le_total.total
/--
If an `LE α` is reflexive, antisymmetric and transitive, then it represents a partial order.
-/
public theorem IsPartialOrder.of_le {α : Type u} [LE α]
(le_refl : Std.Refl (α := α) (· ·) := by exact inferInstance)
(le_antisymm : Std.Antisymm (α := α) (· ·) := by exact inferInstance)
(le_trans : Trans (α := α) (· ·) (· ·) (· ·) := by exact inferInstance) :
IsPartialOrder α where
toIsPreorder := .of_le
le_antisymm := le_antisymm.antisymm
/--
If an `LE α` instance is antisymmetric, transitive and total, then it represents a linear order.
-/
public theorem IsLinearOrder.of_le {α : Type u} [LE α]
(le_antisymm : Std.Antisymm (α := α) (· ·) := by exact inferInstance)
(le_trans : Trans (α := α) (· ·) (· ·) (· ·) := by exact inferInstance)
(le_total : Total (α := α) (· ·) := by exact inferInstance) :
IsLinearOrder α where
toIsLinearPreorder := .of_le
le_antisymm := le_antisymm.antisymm
/--
Returns a `LawfulOrderLT α` instance given certain properties.
If an `OrderData α` instance is compatible with an `LE α` instance, then this lemma derives
a `LawfulOrderLT α` instance from a property relating the `LE α` and `LT α` instances.
-/
public theorem LawfulOrderLT.of_le {α : Type u} [LT α] [LE α]
(lt_iff : a b : α, a < b a b ¬ b a) : LawfulOrderLT α where
lt_iff := lt_iff
/--
This lemma characterizes in terms of `LE α` when a `Min α` instance "behaves like an infimum
operator".
-/
public theorem LawfulOrderInf.of_le {α : Type u} [Min α] [LE α]
(le_min_iff : a b c : α, a min b c a b a c) : LawfulOrderInf α where
le_min_iff := le_min_iff
/--
Returns a `LawfulOrderMin α` instance given certain properties.
This lemma derives a `LawfulOrderMin α` instance from two properties involving `LE α` and `Min α`
instances.
The produced instance entails `LawfulOrderInf α` and `MinEqOr α`.
-/
public theorem LawfulOrderMin.of_le {α : Type u} [Min α] [LE α]
(le_min_iff : a b c : α, a min b c a b a c)
(min_eq_or : a b : α, min a b = a min a b = b) : LawfulOrderMin α where
toLawfulOrderInf := .of_le le_min_iff
toMinEqOr := min_eq_or
/--
This lemma characterizes in terms of `LE α` when a `Max α` instance "behaves like a supremum
operator".
-/
public def LawfulOrderSup.of_le {α : Type u} [Max α] [LE α]
(max_le_iff : a b c : α, max a b c a c b c) : LawfulOrderSup α where
max_le_iff := max_le_iff
/--
Returns a `LawfulOrderMax α` instance given certain properties.
This lemma derives a `LawfulOrderMax α` instance from two properties involving `LE α` and `Max α`
instances.
The produced instance entails `LawfulOrderSup α` and `MaxEqOr α`.
-/
public def LawfulOrderMax.of_le {α : Type u} [Max α] [LE α]
(max_le_iff : a b c : α, max a b c a c b c)
(max_eq_or : a b : α, max a b = a max a b = b) : LawfulOrderMax α where
toLawfulOrderSup := .of_le max_le_iff
toMaxEqOr := max_eq_or
end OfLE
section OfLT
/--
Creates a *total* `LE α` instance from an `LT α` instance.
This only makes sense for asymmetric `LT α` instances (see `Std.Asymm`).
-/
public def LE.ofLT (α : Type u) [LT α] : LE α where
le a b := ¬ b < a
/--
The `LE α` instance obtained from an asymmetric `LT α` instance is compatible with said
`LT α` instance.
-/
public instance LawfulOrderLT.of_lt {α : Type u} [LT α] [i : Asymm (α := α) (· < ·)] :
haveI := LE.ofLT α
LawfulOrderLT α :=
letI := LE.ofLT α
{ lt_iff a b := by simpa [LE.ofLT, Classical.not_not] using i.asymm a b }
/--
If an `LT α` instance is asymmetric and its negation is transitive, then `LE.ofLT α` represents a
linear preorder.
-/
public theorem IsLinearPreorder.of_lt {α : Type u} [LT α]
(lt_asymm : Asymm (α := α) (· < ·) := by exact inferInstance)
(not_lt_trans : Trans (α := α) (¬ · < ·) (¬ · < ·) (¬ · < ·) := by exact inferInstance) :
haveI := LE.ofLT α
IsLinearPreorder α :=
letI := LE.ofLT α
{ le_trans := by simpa [LE.ofLT] using fun a b c hab hbc => not_lt_trans.trans hbc hab
le_total a b := by
apply Or.symm
open Classical in simpa [LE.ofLT, Decidable.imp_iff_not_or] using lt_asymm.asymm a b
le_refl a := by
open Classical in simpa [LE.ofLT] using lt_asymm.asymm a a }
/--
If an `LT α` instance is asymmetric and its negation is transitive and antisymmetric, then
`LE.ofLT α` represents a linear order.
-/
public theorem IsLinearOrder.of_lt {α : Type u} [LT α]
(lt_asymm : Asymm (α := α) (· < ·) := by exact inferInstance)
(not_lt_trans : Trans (α := α) (¬ · < ·) (¬ · < ·) (¬ · < ·) := by exact inferInstance)
(not_lt_antisymm : Antisymm (α := α) (¬ · < ·) := by exact inferInstance) :
haveI := LE.ofLT α
IsLinearOrder α :=
letI := LE.ofLT α
haveI : IsLinearPreorder α := .of_lt
{ le_antisymm := by
simpa [LE.ofLT] using fun a b hab hba => not_lt_antisymm.antisymm a b hba hab }
/--
This lemma characterizes in terms of `LT α` when a `Min α` instance
"behaves like an infimum operator" with respect to `LE.ofLT α`.
-/
public theorem LawfulOrderInf.of_lt {α : Type u} [Min α] [LT α]
(min_lt_iff : a b c : α, min b c < a b < a c < a) :
haveI := LE.ofLT α
LawfulOrderInf α :=
letI := LE.ofLT α
{ le_min_iff a b c := by
open Classical in
simp only [LE.ofLT, Decidable.not_iff_not (a := ¬ min b c < a)]
simpa [Decidable.imp_iff_not_or] using min_lt_iff a b c }
/--
Derives a `LawfulOrderMin α` instance for `OrderData.ofLT` from two properties involving
`LT α` and `Min α` instances.
The produced instance entails `LawfulOrderInf α` and `MinEqOr α`.
-/
public theorem LawfulOrderMin.of_lt {α : Type u} [Min α] [LT α]
(min_lt_iff : a b c : α, min b c < a b < a c < a)
(min_eq_or : a b : α, min a b = a min a b = b) :
haveI := LE.ofLT α
LawfulOrderMin α :=
letI := LE.ofLT α
{ toLawfulOrderInf := .of_lt min_lt_iff
toMinEqOr := min_eq_or }
/--
This lemma characterizes in terms of `LT α` when a `Max α` instance
"behaves like an supremum operator" with respect to `OrderData.ofLT α`.
-/
public def LawfulOrderSup.of_lt {α : Type u} [Max α] [LT α]
(lt_max_iff : a b c : α, c < max a b c < a c < b) :
haveI := LE.ofLT α
LawfulOrderSup α :=
letI := LE.ofLT α
{ max_le_iff a b c := by
open Classical in
simp only [LE.ofLT, Decidable.not_iff_not ( a := ¬ c < max a b)]
simpa [Decidable.imp_iff_not_or] using lt_max_iff a b c }
/--
Derives a `LawfulOrderMax α` instance for `OrderData.ofLT` from two properties involving `LT α` and
`Max α` instances.
The produced instance entails `LawfulOrderSup α` and `MaxEqOr α`.
-/
public def LawfulOrderMax.of_lt {α : Type u} [Max α] [LT α]
(lt_max_iff : a b c : α, c < max a b c < a c < b)
(max_eq_or : a b : α, max a b = a max a b = b) :
haveI := LE.ofLT α
LawfulOrderMax α :=
letI := LE.ofLT α
{ toLawfulOrderSup := .of_lt lt_max_iff
toMaxEqOr := max_eq_or }
end OfLT
end Std

View File

@@ -1,342 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Order.Classes
public import Init.Data.Order.Factories
import Init.SimpLemmas
import Init.Classical
namespace Std
/-!
This module provides typeclass instances and lemmas about order-related typeclasses.
-/
section AxiomaticInstances
public instance (r : α α Prop) [Asymm r] : Irrefl r where
irrefl a h := Asymm.asymm a a h h
public instance {r : α α Prop} [Total r] : Refl r where
refl a := by simpa using Total.total a a
public instance Total.asymm_of_total_not {r : α α Prop} [i : Total (¬ r · ·)] : Asymm r where
asymm a b h := by cases i.total a b <;> trivial
public theorem Asymm.total_not {r : α α Prop} [i : Asymm r] : Total (¬ r · ·) where
total a b := by
apply Classical.byCases (p := r a b) <;> intro hab
· exact Or.inr <| i.asymm a b hab
· exact Or.inl hab
public instance {α : Type u} [LE α] [IsPartialOrder α] :
Std.Antisymm (α := α) (· ·) where
antisymm := IsPartialOrder.le_antisymm
public instance {α : Type u} [LE α] [IsPreorder α] :
Trans (α := α) (· ·) (· ·) (· ·) where
trans := IsPreorder.le_trans _ _ _
public instance {α : Type u} [LE α] [IsPreorder α] :
Std.Refl (α := α) (· ·) where
refl a := IsPreorder.le_refl a
public instance {α : Type u} [LE α] [IsLinearPreorder α] :
Std.Total (α := α) (· ·) where
total a b := IsLinearPreorder.le_total a b
end AxiomaticInstances
section LE
public theorem le_refl {α : Type u} [LE α] [Refl (α := α) (· ·)] (a : α) : a a := by
simp [Refl.refl]
public theorem le_antisymm {α : Type u} [LE α] [Std.Antisymm (α := α) (· ·)] {a b : α}
(hab : a b) (hba : b a) : a = b :=
Std.Antisymm.antisymm _ _ hab hba
public theorem le_trans {α : Type u} [LE α] [Trans (α := α) (· ·) (· ·) (· ·)] {a b c : α}
(hab : a b) (hbc : b c) : a c :=
Trans.trans hab hbc
public theorem le_total {α : Type u} [LE α] [Std.Total (α := α) (· ·)] {a b : α} :
a b b a :=
Std.Total.total a b
public instance {α : Type u} [LE α] [IsPreorder α] :
Refl (α := α) (· ·) where
refl := IsPreorder.le_refl
public instance {α : Type u} [LE α] [IsPreorder α] :
Trans (α := α) (· ·) (· ·) (· ·) where
trans := IsPreorder.le_trans _ _ _
public instance {α : Type u} [LE α] [IsLinearPreorder α] :
Total (α := α) (· ·) where
total := IsLinearPreorder.le_total
public instance {α : Type u} [LE α] [IsPartialOrder α] :
Antisymm (α := α) (· ·) where
antisymm := IsPartialOrder.le_antisymm
end LE
section LT
public theorem lt_iff_le_and_not_ge {α : Type u} [LT α] [LE α] [LawfulOrderLT α] {a b : α} :
a < b a b ¬ b a :=
LawfulOrderLT.lt_iff a b
public theorem not_lt {α : Type u} [LT α] [LE α] [Std.Total (α := α) (· ·)] [LawfulOrderLT α]
{a b : α} : ¬ a < b b a := by
simp [lt_iff_le_and_not_ge, Classical.not_not, Std.Total.total]
public theorem not_gt_of_lt {α : Type u} [LT α] [i : Std.Asymm (α := α) (· < ·)] {a b : α}
(h : a < b) : ¬ b < a :=
i.asymm a b h
public instance {α : Type u} [LT α] [LE α] [LawfulOrderLT α] :
Std.Asymm (α := α) (· < ·) where
asymm a b := by
simp only [LawfulOrderLT.lt_iff]
intro h h'
exact h.2.elim h'.1
public instance {α : Type u} [LT α] [LE α] [IsPreorder α] [LawfulOrderLT α] :
Std.Irrefl (α := α) (· < ·) := inferInstance
public instance {α : Type u} [LT α] [LE α]
[Trans (α := α) (· ·) (· ·) (· ·) ] [LawfulOrderLT α] :
Trans (α := α) (· < ·) (· < ·) (· < ·) where
trans {a b c} hab hbc := by
simp only [lt_iff_le_and_not_ge] at hab hbc
apply And.intro
· exact le_trans hab.1 hbc.1
· intro hca
exact hab.2.elim (le_trans hbc.1 hca)
public instance {α : Type u} {_ : LT α} [LE α] [LawfulOrderLT α]
[Total (α := α) (· ·)] [Antisymm (α := α) (· ·)] :
Antisymm (α := α) (¬ · < ·) where
antisymm a b hab hba := by
simp only [not_lt] at hab hba
exact Antisymm.antisymm (r := (· ·)) a b hba hab
public instance {α : Type u} {_ : LT α} [LE α] [LawfulOrderLT α]
[Total (α := α) (· ·)] [Trans (α := α) (· ·) (· ·) (· ·)] :
Trans (α := α) (¬ · < ·) (¬ · < ·) (¬ · < ·) where
trans {a b c} hab hbc := by
simp only [not_lt] at hab hbc
exact le_trans hbc hab
public instance {α : Type u} {_ : LT α} [LE α] [LawfulOrderLT α] [Total (α := α) (· ·)] :
Total (α := α) (¬ · < ·) where
total a b := by simp [not_lt, Std.Total.total]
public theorem lt_of_le_of_lt {α : Type u} [LE α] [LT α]
[Trans (α := α) (· ·) (· ·) (· ·)] [LawfulOrderLT α] {a b c : α} (hab : a b)
(hbc : b < c) : a < c := by
simp only [lt_iff_le_and_not_ge] at hbc
apply And.intro
· exact le_trans hab hbc.1
· intro hca
exact hbc.2.elim (le_trans hca hab)
public theorem lt_of_le_of_ne {α : Type u} [LE α] [LT α]
[Std.Antisymm (α := α) (· ·)] [LawfulOrderLT α] {a b : α}
(hle : a b) (hne : a b) : a < b := by
apply Classical.byContradiction
simp only [lt_iff_le_and_not_ge, hle, true_and, Classical.not_not, imp_false]
intro hge
exact hne.elim <| Std.Antisymm.antisymm a b hle hge
end LT
end Std
namespace Classical.Order
open Std
public scoped instance instLT {α : Type u} [LE α] :
LT α where
lt a b := a b ¬ b a
public instance instLawfulOrderLT {α : Type u} [LE α] :
LawfulOrderLT α where
lt_iff _ _ := Iff.rfl
end Classical.Order
namespace Std
section Min
public theorem min_self {α : Type u} [Min α] [Std.IdempotentOp (min : α α α)] {a : α} :
min a a = a :=
Std.IdempotentOp.idempotent a
public theorem le_min_iff {α : Type u} [Min α] [LE α]
[LawfulOrderInf α] {a b c : α} :
a min b c a b a c :=
LawfulOrderInf.le_min_iff a b c
public theorem min_le_left {α : Type u} [Min α] [LE α] [Refl (α := α) (· ·)] [LawfulOrderInf α]
{a b : α} : min a b a :=
le_min_iff.mp (le_refl _) |>.1
public theorem min_le_right {α : Type u} [Min α] [LE α] [Refl (α := α) (· ·)] [LawfulOrderInf α]
{a b : α} : min a b b :=
le_min_iff.mp (le_refl _) |>.2
public theorem min_le {α : Type u} [Min α] [LE α] [IsPreorder α] [LawfulOrderMin α] {a b c : α} :
min a b c a c b c := by
cases MinEqOr.min_eq_or a b <;> rename_i h
· simpa [h] using le_trans (h min_le_right (a := a) (b := b))
· simpa [h] using le_trans (h min_le_left (a := a) (b := b))
public theorem min_eq_or {α : Type u} [Min α] [MinEqOr α] {a b : α} :
min a b = a min a b = b :=
MinEqOr.min_eq_or a b
public instance {α : Type u} [LE α] [Min α] [IsLinearOrder α] [LawfulOrderInf α] :
MinEqOr α where
min_eq_or a b := by
open Classical.Order in
cases le_total (a := a) (b := b)
· apply Or.inl
apply le_antisymm
· apply min_le_left
· rw [le_min_iff]
exact le_refl a, _
· apply Or.inr
apply le_antisymm
· apply min_le_right
· rw [le_min_iff]
exact _, le_refl b
/--
If a `Min α` instance satisfies typical properties in terms of a reflexive and antisymmetric `LE α`
instance, then the `LE α` instance represents a linear order.
-/
public theorem IsLinearOrder.of_refl_of_antisymm_of_lawfulOrderMin {α : Type u} [LE α]
[LE α] [Min α] [Refl (α := α) (· ·)] [Antisymm (α := α) (· ·)] [LawfulOrderMin α] :
IsLinearOrder α := by
apply IsLinearOrder.of_le
· infer_instance
· constructor
intro a b c hab hbc
have : b = min b c := by
apply le_antisymm
· rw [le_min_iff]
exact le_refl b, hbc
· apply min_le_left
rw [this, le_min_iff] at hab
exact hab.2
· constructor
intro a b
cases min_eq_or (a := a) (b := b) <;> rename_i h
· exact Or.inl (h min_le_right)
· exact Or.inr (h min_le_left)
public instance {α : Type u} [Min α] [MinEqOr α] :
Std.IdempotentOp (min : α α α) where
idempotent a := by cases MinEqOr.min_eq_or a a <;> assumption
open Classical.Order in
public instance {α : Type u} [LE α] [Min α] [IsLinearOrder α] [LawfulOrderMin α] :
Std.Associative (min : α α α) where
assoc a b c := by apply le_antisymm <;> simp [min_le, le_min_iff, le_refl]
end Min
section Max
public theorem max_self {α : Type u} [Max α] [Std.IdempotentOp (max : α α α)] {a : α} :
max a a = a :=
Std.IdempotentOp.idempotent a
public theorem max_le_iff {α : Type u} [Max α] [LE α] [LawfulOrderSup α] {a b c : α} :
max a b c a c b c :=
LawfulOrderSup.max_le_iff a b c
public theorem left_le_max {α : Type u} [Max α] [LE α] [Refl (α := α) (· ·)] [LawfulOrderSup α]
{a b : α} : a max a b :=
max_le_iff.mp (le_refl _) |>.1
public theorem right_le_max {α : Type u} [Max α] [LE α] [Refl (α := α) (· ·)]
[LawfulOrderSup α] {a b : α} : b max a b :=
max_le_iff.mp (le_refl _) |>.2
public theorem le_max {α : Type u} [Max α] [LE α] [IsPreorder α] [LawfulOrderMax α] {a b c : α} :
a max b c a b a c := by
cases MaxEqOr.max_eq_or b c <;> rename_i h
· simpa [h] using (le_trans · (h right_le_max))
· simpa [h] using (le_trans · (h left_le_max))
public theorem max_eq_or {α : Type u} [Max α] [MaxEqOr α] {a b : α} :
max a b = a max a b = b :=
MaxEqOr.max_eq_or a b
public instance {α : Type u} [LE α] [Max α] [IsLinearOrder α] [LawfulOrderSup α] :
MaxEqOr α where
max_eq_or a b := by
open Classical.Order in
cases le_total (a := a) (b := b)
· apply Or.inr
apply le_antisymm
· rw [max_le_iff]
exact _, le_refl b
· apply right_le_max
· apply Or.inl
apply le_antisymm
· rw [max_le_iff]
exact le_refl a, _
· apply left_le_max
/--
If a `Max α` instance satisfies typical properties in terms of a reflexive and antisymmetric `LE α`
instance, then the `LE α` instance represents a linear order.
-/
public theorem IsLinearOrder.of_refl_of_antisymm_of_lawfulOrderMax {α : Type u} [LE α] [Max α]
[Refl (α := α) (· ·)] [Antisymm (α := α) (· ·)] [LawfulOrderMax α] :
IsLinearOrder α := by
apply IsLinearOrder.of_le
· infer_instance
· constructor
intro a b c hab hbc
have : b = max a b := by
apply le_antisymm
· exact right_le_max
· rw [max_le_iff]
exact hab, le_refl b
rw [this, max_le_iff] at hbc
exact hbc.1
· constructor
intro a b
cases max_eq_or (a := a) (b := b) <;> rename_i h
· exact Or.inr (h right_le_max)
· exact Or.inl (h left_le_max)
public instance {α : Type u} [Max α] [MaxEqOr α] {P : α Prop} : Max (Subtype P) where
max a b := Max.max a.val b.val, MaxEqOr.elim a.property b.property
public instance {α : Type u} [Max α] [MaxEqOr α] :
Std.IdempotentOp (max : α α α) where
idempotent a := by cases MaxEqOr.max_eq_or a a <;> assumption
open Classical.Order in
public instance {α : Type u} [LE α] [Max α] [IsLinearOrder α] [LawfulOrderMax α] :
Std.Associative (max : α α α) where
assoc a b c := by
apply le_antisymm
all_goals
simp only [max_le_iff]
simp [le_max, le_refl]
end Max
end Std

View File

@@ -15,12 +15,9 @@ public import Init.Data.Int.LemmasAux
public import all Init.Data.UInt.Basic
public import Init.Data.UInt.Lemmas
public import Init.System.Platform
import Init.Data.Order.Lemmas
public section
open Std
open Lean in
set_option hygiene false in
macro "declare_int_theorems" typeName:ident _bits:term:arg : command => do
@@ -3028,56 +3025,6 @@ protected theorem Int64.lt_asymm {a b : Int64} : a < b → ¬b < a :=
protected theorem ISize.lt_asymm {a b : ISize} : a < b ¬b < a :=
fun hab hba => ISize.lt_irrefl (ISize.lt_trans hab hba)
instance Int8.instIsLinearOrder : IsLinearOrder Int8 := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Int8.le_antisymm
case le_total => constructor; apply Int8.le_total
case le_trans => constructor; apply Int8.le_trans
instance : LawfulOrderLT Int8 where
lt_iff := by
simp [ Int8.not_le, Decidable.imp_iff_not_or, Std.Total.total]
instance Int16.instIsLinearOrder : IsLinearOrder Int16 := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Int16.le_antisymm
case le_total => constructor; apply Int16.le_total
case le_trans => constructor; apply Int16.le_trans
instance : LawfulOrderLT Int16 where
lt_iff := by
simp [ Int16.not_le, Decidable.imp_iff_not_or, Std.Total.total]
instance Int32.instIsLinearOrder : IsLinearOrder Int32 := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Int32.le_antisymm
case le_total => constructor; apply Int32.le_total
case le_trans => constructor; apply Int32.le_trans
instance : LawfulOrderLT Int32 where
lt_iff := by
simp [ Int32.not_le, Decidable.imp_iff_not_or, Std.Total.total]
instance Int64.instIsLinearOrder : IsLinearOrder Int64 := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Int64.le_antisymm
case le_total => constructor; apply Int64.le_total
case le_trans => constructor; apply Int64.le_trans
instance : LawfulOrderLT Int64 where
lt_iff := by
simp [ Int64.not_le, Decidable.imp_iff_not_or, Std.Total.total]
instance ISize.instIsLinearOrder : IsLinearOrder ISize := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply ISize.le_antisymm
case le_total => constructor; apply ISize.le_total
case le_trans => constructor; apply ISize.le_trans
instance : LawfulOrderLT ISize where
lt_iff := by
simp [ ISize.not_le, Decidable.imp_iff_not_or, Std.Total.total]
protected theorem Int8.add_neg_eq_sub {a b : Int8} : a + -b = a - b := Int8.toBitVec_inj.1 BitVec.add_neg_eq_sub
protected theorem Int16.add_neg_eq_sub {a b : Int16} : a + -b = a - b := Int16.toBitVec_inj.1 BitVec.add_neg_eq_sub
protected theorem Int32.add_neg_eq_sub {a b : Int32} : a + -b = a - b := Int32.toBitVec_inj.1 BitVec.add_neg_eq_sub

View File

@@ -6,15 +6,11 @@ Authors: Leonardo de Moura
module
prelude
public import Init.Data.Char.Order
public import Init.Data.Char.Lemmas
public import Init.Data.List.Lex
import Init.Data.Order.Lemmas
public section
open Std
namespace String
protected theorem data_eq_of_eq {a b : String} (h : a = b) : a.data = b.data :=
@@ -38,14 +34,4 @@ protected theorem ne_of_lt {a b : String} (h : a < b) : a ≠ b := by
have := String.lt_irrefl a
intro h; subst h; contradiction
instance instIsLinearOrder : IsLinearOrder String := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply String.le_antisymm
case le_trans => constructor; apply String.le_trans
case le_total => constructor; apply String.le_total
instance : LawfulOrderLT String where
lt_iff a b := by
simp [ String.not_le, Decidable.imp_iff_not_or, Std.Total.total]
end String

View File

@@ -1,11 +1,32 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
Authors: Johannes Hölzl
-/
module
prelude
public import Init.Data.Subtype.Basic
public import Init.Data.Subtype.Order
public import Init.Data.Subtype.OrderExtra
public import Init.Ext
public import Init.Core
public section
namespace Subtype
universe u
variable {α : Sort u} {p q : α Prop}
@[ext]
protected theorem ext : {a1 a2 : { x // p x }}, (a1 : α) = (a2 : α) a1 = a2
| _, _, _, _, rfl => rfl
@[simp]
protected theorem «forall» {q : { a // p a } Prop} : ( x, q x) a b, q a, b :=
fun h a b h a, b, fun h a, b h a b
@[simp]
protected theorem «exists» {q : { a // p a } Prop} :
(Exists fun x => q x) Exists fun a => Exists fun b => q a, b :=
fun a, b, h a, b, h, fun a, b, h a, b, h
end Subtype

View File

@@ -1,32 +0,0 @@
/-
Copyright (c) 2017 Johannes Hölzl. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Johannes Hölzl
-/
module
prelude
public import Init.Ext
public import Init.Core
public section
namespace Subtype
universe u
variable {α : Sort u} {p q : α Prop}
@[ext]
protected theorem ext : {a1 a2 : { x // p x }}, (a1 : α) = (a2 : α) a1 = a2
| _, _, _, _, rfl => rfl
@[simp]
protected theorem «forall» {q : { a // p a } Prop} : ( x, q x) a b, q a, b :=
fun h a b h a, b, fun h a, b h a b
@[simp]
protected theorem «exists» {q : { a // p a } Prop} :
(Exists fun x => q x) Exists fun a => Exists fun b => q a, b :=
fun a, b, h a, b, h, fun a, b, h a, b, h
end Subtype

View File

@@ -1,94 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
import Init.SimpLemmas
public import Init.Data.Order.Classes
public import Init.Data.Order.Lemmas
import Init.Data.Order.Factories
import Init.Data.Subtype.Basic
namespace Std
public instance {α : Type u} [LE α] {P : α Prop} : LE (Subtype P) where
le a b := a.val b.val
public instance {α : Type u} [LT α] {P : α Prop} : LT (Subtype P) where
lt a b := a.val < b.val
public instance {α : Type u} [LT α] [LE α] [LawfulOrderLT α]
{P : α Prop} : LawfulOrderLT (Subtype P) where
lt_iff a b := by simp [LT.lt, LE.le, LawfulOrderLT.lt_iff]
public instance {α : Type u} [BEq α] {P : α Prop} : BEq (Subtype P) where
beq a b := a.val == b.val
public instance {α : Type u} [Min α] [MinEqOr α] {P : α Prop} : Min (Subtype P) where
min a b := Min.min a.val b.val, MinEqOr.elim a.property b.property
public instance {α : Type u} [Max α] [MaxEqOr α] {P : α Prop} : Max (Subtype P) where
max a b := max a.val b.val, MaxEqOr.elim a.property b.property
public instance {α : Type u} [LE α] [i : Refl (α := α) (· ·)] {P : α Prop} :
Refl (α := Subtype P) (· ·) where
refl a := i.refl a.val
public instance {α : Type u} [LE α] [i : Antisymm (α := α) (· ·)] {P : α Prop} :
Antisymm (α := Subtype P) (· ·) where
antisymm a b hab hba := private Subtype.ext <| i.antisymm a.val b.val hab hba
public instance {α : Type u} [LE α] [i : Total (α := α) (· ·)] {P : α Prop} :
Total (α := Subtype P) (· ·) where
total a b := i.total a.val b.val
public instance {α : Type u} [LE α] [i : Trans (α := α) (· ·) (· ·) (· ·)]
{P : α Prop} :
Trans (α := Subtype P) (· ·) (· ·) (· ·) where
trans := i.trans
public instance {α : Type u} [Min α] [MinEqOr α] {P : α Prop} :
MinEqOr (Subtype P) where
min_eq_or a b := by
cases min_eq_or (a := a.val) (b := b.val) <;> rename_i h
· exact Or.inl <| Subtype.ext h
· exact Or.inr <| Subtype.ext h
public instance {α : Type u} [LE α] [Min α] [LawfulOrderMin α] {P : α Prop} :
LawfulOrderMin (Subtype P) where
le_min_iff _ _ _ := by
exact le_min_iff (α := α)
public instance {α : Type u} [Max α] [MaxEqOr α] {P : α Prop} :
MaxEqOr (Subtype P) where
max_eq_or a b := by
cases max_eq_or (a := a.val) (b := b.val) <;> rename_i h
· exact Or.inl <| Subtype.ext h
· exact Or.inr <| Subtype.ext h
public instance {α : Type u} [LE α] [Max α] [LawfulOrderMax α] {P : α Prop} :
LawfulOrderMax (Subtype P) where
max_le_iff _ _ _ := by
open Classical.Order in
exact max_le_iff (α := α)
public instance {α : Type u} [LE α] [IsPreorder α] {P : α Prop} :
IsPreorder (Subtype P) :=
IsPreorder.of_le
public instance {α : Type u} [LE α] [IsLinearPreorder α] {P : α Prop} :
IsLinearPreorder (Subtype P) :=
IsLinearPreorder.of_le
public instance {α : Type u} [LE α] [IsPartialOrder α] {P : α Prop} :
IsPartialOrder (Subtype P) :=
IsPartialOrder.of_le
public instance {α : Type u} [LE α] [IsLinearOrder α] {P : α Prop} :
IsLinearOrder (Subtype P) :=
IsLinearOrder.of_le
end Std

View File

@@ -1,13 +0,0 @@
/-
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Paul Reichert
-/
module
prelude
public import Init.Data.Subtype.Order
public import Init.Data.Ord
public instance {α : Type u} [Ord α] {P : α Prop} : Ord (Subtype P) where
compare a b := compare a.val b.val

View File

@@ -8,13 +8,9 @@ module
prelude
public import Init.Data.UInt.BasicAux
public import Init.Data.BitVec.Basic
public import Init.Data.Order.Classes
import Init.Data.Order.Factories
@[expose] public section
open Std
set_option linter.missingDocs true
open Nat

View File

@@ -15,13 +15,9 @@ public import all Init.Data.BitVec.Basic
public import Init.Data.BitVec.Lemmas
public import Init.Data.Nat.Div.Lemmas
public import Init.System.Platform
public import Init.Data.Order.Factories
import Init.Data.Order.Lemmas
public section
open Std
open Lean in
set_option hygiene false in
macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
@@ -210,19 +206,6 @@ macro "declare_uint_theorems" typeName:ident bits:term:arg : command => do
protected theorem le_antisymm {a b : $typeName} (h₁ : a b) (h₂ : b a) : a = b :=
le_antisymm_iff.2 h₁, h₂
open $typeName renaming
le_refl le_refl', le_antisymm le_antisymm', le_total le_total', le_trans le_trans' in
instance instIsLinearOrder : IsLinearOrder $typeName := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply le_antisymm'
case le_total => constructor; apply le_total'
case le_trans => constructor; apply le_trans'
open $typeName renaming not_le not_le'
instance : LawfulOrderLT $typeName where
lt_iff _ _ := by
simp [ not_le', Decidable.imp_iff_not_or, Std.Total.total]
@[simp] protected theorem ofNat_one : ofNat 1 = 1 := (rfl)
@[simp] protected theorem ofNat_toNat {x : $typeName} : ofNat x.toNat = x := by

View File

@@ -11,17 +11,15 @@ public import Init.Data.Vector.Lemmas
public import all Init.Data.Array.Lex.Basic
public import Init.Data.Array.Lex.Lemmas
import Init.Data.Range.Polymorphic.Lemmas
import Init.Data.Order.Lemmas
public section
open Std
set_option linter.listVariables true -- Enforce naming conventions for `List`/`Array`/`Vector` variables.
set_option linter.indexVariables true -- Enforce naming conventions for index variables.
namespace Vector
/-! ### Lexicographic ordering -/
@[simp] theorem lt_toArray [LT α] {xs ys : Vector α n} : xs.toArray < ys.toArray xs < ys := Iff.rfl
@@ -98,35 +96,27 @@ 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 α] [LE α] [LawfulOrderLT α] [IsLinearOrder α]
protected theorem lt_of_le_of_lt [LT α]
[i₀ : Std.Irrefl (· < · : α α Prop)]
[i₁ : Std.Asymm (· < · : α α Prop)]
[i₂ : Std.Antisymm (¬ · < · : α α Prop)]
[i₃ : Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Vector α n} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
Array.lt_of_le_of_lt h₁ h₂
@[deprecated Vector.lt_of_le_of_lt (since := "2025-08-01")]
protected theorem lt_of_le_of_lt' [LT α]
protected theorem le_trans [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Vector α n} (h₁ : xs ys) (h₂ : ys < zs) : xs < zs :=
letI := LE.ofLT α
haveI : IsLinearOrder α := IsLinearOrder.of_lt
Array.lt_of_le_of_lt h₁ h₂
protected theorem le_trans [LT α] [LE α] [LawfulOrderLT α] [IsLinearOrder α]
{xs ys zs : Vector α n} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
fun h₃ => h₁ (Vector.lt_of_le_of_lt h₂ h₃)
@[deprecated Vector.le_trans (since := "2025-08-01")]
protected theorem le_trans' [LT α]
instance [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)]
{xs ys zs : Vector α n} (h₁ : xs ys) (h₂ : ys zs) : xs zs :=
letI := LE.ofLT α
haveI : IsLinearOrder α := IsLinearOrder.of_lt
Array.le_trans h₁ h₂
instance [LT α] [LE α] [LawfulOrderLT α] [IsLinearOrder α] :
[Trans (¬ · < · : α α Prop) (¬ · < ·) (¬ · < ·)] :
Trans (· · : Vector α n Vector α n Prop) (· ·) (· ·) where
trans h₁ h₂ := Vector.le_trans h₁ h₂
@@ -139,44 +129,30 @@ instance [LT α]
Std.Asymm (· < · : Vector α n Vector α n Prop) where
asymm _ _ := Vector.lt_asymm
protected theorem le_total [LT α] [i : Std.Asymm (· < · : α α Prop)] (xs ys : Vector α n) :
xs ys ys xs :=
protected theorem le_total [LT α]
[i : Std.Total (¬ · < · : α α Prop)] (xs ys : Vector α n) : xs ys ys xs :=
Array.le_total _ _
protected theorem le_antisymm [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α]
{xs ys : Vector α n} (h₁ : xs ys) (h₂ : ys xs) : xs = ys :=
Vector.toArray_inj.mp <| Array.le_antisymm h₁ h₂
instance [LT α] [Std.Asymm (· < · : α α Prop)] :
instance [LT α]
[Std.Total (¬ · < · : α α Prop)] :
Std.Total (· · : Vector α n Vector α n Prop) where
total := Vector.le_total
instance [LT α] [LE α] [IsLinearOrder α] [LawfulOrderLT α] :
IsLinearOrder (Vector α n) := by
apply IsLinearOrder.of_le
case le_antisymm => constructor; apply Vector.le_antisymm
case le_total => constructor; apply Vector.le_total
case le_trans => constructor; apply Vector.le_trans
@[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
instance [LT α] [Std.Asymm (· < · : α α Prop)] : LawfulOrderLT (Vector α n) where
lt_iff _ _ := by
open Classical in
simp [ Vector.not_le, Decidable.imp_iff_not_or, Std.Total.total]
protected theorem le_of_lt [LT α]
[i : Std.Asymm (· < · : α α Prop)]
[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 α]
[Std.Asymm (· < · : α α Prop)]
[Std.Irrefl (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Total (¬ · < · : α α Prop)]
{xs ys : Vector α n} : xs ys xs < ys xs = ys := by
simpa using Array.le_iff_lt_or_eq (xs := xs.toArray) (ys := ys.toArray)
@@ -246,6 +222,7 @@ protected theorem lt_iff_exists [LT α] {xs ys : Vector α n} :
simp_all [Array.lt_iff_exists]
protected theorem le_iff_exists [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)] {xs ys : Vector α n} :
xs ys
@@ -260,6 +237,7 @@ theorem append_left_lt [LT α] {xs : Vector α n} {ys ys' : Vector α m} (h : ys
simpa using Array.append_left_lt h
theorem append_left_le [LT α]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
{xs : Vector α n} {ys ys' : Vector α m} (h : ys ys') :
@@ -272,8 +250,10 @@ protected theorem map_lt [LT α] [LT β]
simpa using Array.map_lt w h
protected theorem map_le [LT α] [LT β]
[Std.Irrefl (· < · : α α Prop)]
[Std.Asymm (· < · : α α Prop)]
[Std.Antisymm (¬ · < · : α α Prop)]
[Std.Irrefl (· < · : β β Prop)]
[Std.Asymm (· < · : β β Prop)]
[Std.Antisymm (¬ · < · : β β Prop)]
{xs ys : Vector α n} {f : α β} (w : x y, x < y f x < f y) (h : xs ys) :

View File

@@ -20,9 +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
/-- A type with zero and addition,
where addition is commutative and associative,
and the zero is the right identity for addition. -/
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
@@ -33,9 +30,6 @@ class AddCommMonoid (M : Type u) extends Zero M, Add M where
attribute [instance 100] AddCommMonoid.toZero AddCommMonoid.toAdd
/-- A type with zero, addition, negation, and subtraction,
where addition is commutative and associative,
and negation is the left inverse of addition. -/
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

View File

@@ -267,7 +267,7 @@ instance [NatModule α] [AddRightCancel α] [NoNatZeroDivisors α] : NoNatZeroDi
replace h₂ := NoNatZeroDivisors.no_nat_zero_divisors k (a₁ + b₂) (a₂ + b₁) h₁ h₂
apply Quot.sound; simp [r]; exists 0; simp [h₂]
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : LE (OfNatModule.Q α) where
instance [Preorder α] [OrderedAdd α] : LE (OfNatModule.Q α) where
le a b := Q.liftOn₂ a b (fun (a, b) (c, d) => a + d b + c)
(by intro (a₁, b₁) (a₂, b₂) (a₃, b₃) (a₄, b₄)
simp; intro k₁ h₁ k₂ h₂
@@ -283,14 +283,11 @@ instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : LE (OfNatModule.Q α) w
rw [this]; clear this
rw [ OrderedAdd.add_le_left_iff])
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : LT (OfNatModule.Q α) where
lt a b := a b ¬b a
@[local simp] theorem mk_le_mk [LE α] [LT α] [Preorder α] [OrderedAdd α] {a₁ a₂ b₁ b₂ : α} :
@[local simp] theorem mk_le_mk [Preorder α] [OrderedAdd α] {a₁ a₂ b₁ b₂ : α} :
Q.mk (a₁, a₂) Q.mk (b₁, b₂) a₁ + b₂ a₂ + b₁ := by
rfl
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : Preorder (OfNatModule.Q α) where
instance [Preorder α] [OrderedAdd α] : Preorder (OfNatModule.Q α) where
le_refl a := by
obtain a₁, a₂ := a
change Q.mk _ Q.mk _
@@ -311,24 +308,24 @@ instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : Preorder (OfNatModule.Q
attribute [-simp] Q.mk
@[local simp] private theorem mk_lt_mk [LE α] [LT α] [Preorder α] [OrderedAdd α] {a₁ a₂ b₁ b₂ : α} :
@[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]
@[local simp] private theorem mk_pos [LE α] [LT α] [Preorder α] [OrderedAdd α] {a₁ a₂ : α} :
@[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]
@[local simp]
theorem toQ_le [LE α] [LT α] [Preorder α] [OrderedAdd α] {a b : α} : toQ a toQ b a b := by
theorem toQ_le [Preorder α] [OrderedAdd α] {a b : α} : toQ a toQ b a b := by
simp
@[local simp]
theorem toQ_lt [LE α] [LT α] [Preorder α] [OrderedAdd α] {a b : α} : toQ a < toQ b a < b := by
theorem toQ_lt [Preorder α] [OrderedAdd α] {a b : α} : toQ a < toQ b a < b := by
simp [Preorder.lt_iff_le_not_le]
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : OrderedAdd (OfNatModule.Q α) where
instance [Preorder α] [OrderedAdd α] : OrderedAdd (OfNatModule.Q α) where
add_le_left_iff := by
intro a b c
obtain a₁, a₂ := a

View File

@@ -15,7 +15,7 @@ namespace Lean.Grind
namespace Field.IsOrdered
variable {R : Type u} [Field R] [LE R] [LT R] [LinearOrder R] [OrderedRing R]
variable {R : Type u} [Field R] [LinearOrder R] [OrderedRing R]
open OrderedAdd
open OrderedRing

View File

@@ -254,17 +254,17 @@ open OrderedAdd
Helper theorems for conflict resolution during model construction.
-/
private theorem le_add_le {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] {a b : α}
private theorem le_add_le {α} [IntModule α] [Preorder α] [OrderedAdd α] {a b : α}
(h₁ : a 0) (h₂ : b 0) : a + b 0 := by
replace h₁ := add_le_left h₁ b; simp at h₁
exact Preorder.le_trans h₁ h₂
private theorem le_add_lt {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] {a b : α}
private theorem le_add_lt {α} [IntModule α] [Preorder α] [OrderedAdd α] {a b : α}
(h₁ : a 0) (h₂ : b < 0) : a + b < 0 := by
replace h₁ := add_le_left h₁ b; simp at h₁
exact Preorder.lt_of_le_of_lt h₁ h₂
private theorem lt_add_lt {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] {a b : α}
private theorem lt_add_lt {α} [IntModule α] [Preorder α] [OrderedAdd α] {a b : α}
(h₁ : a < 0) (h₂ : b < 0) : a + b < 0 := by
replace h₁ := add_lt_left h₁ b; simp at h₁
exact Preorder.lt_trans h₁ h₂
@@ -277,7 +277,7 @@ def le_le_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
let a₂ := p₂.leadCoeff.natAbs
p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
theorem le_le_combine {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
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₁
@@ -289,7 +289,7 @@ def le_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
let a₂ := p₂.leadCoeff.natAbs
a₁ > (0 : Int) && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
theorem le_lt_combine {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
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₁
@@ -301,7 +301,7 @@ def lt_lt_combine_cert (p₁ p₂ p₃ : Poly) : Bool :=
let a₂ := p₂.leadCoeff.natAbs
a₂ > (0 : Int) && a₁ > (0 : Int) && p₃ == (p₁.mul a₂ |>.combine (p₂.mul a₁))
theorem lt_lt_combine {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ p₃ : Poly)
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₁
@@ -312,7 +312,7 @@ def diseq_split_cert (p₁ p₂ : Poly) : Bool :=
p₂ == p₁.mul (-1)
-- We need `LinearOrder` to use `trichotomy`
theorem diseq_split {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly)
theorem diseq_split {α} [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
simp [diseq_split_cert]; intro _ h₁; subst p₂; simp
cases LinearOrder.trichotomy (p₁.denote ctx) 0
@@ -322,7 +322,7 @@ theorem diseq_split {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [Ordere
simp [h₁] at h
rw [ neg_pos_iff, neg_zsmul, neg_neg, one_zsmul]; assumption
theorem diseq_split_resolve {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly)
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
intro h₁ h₂ h₃
exact (diseq_split ctx p₁ p₂ h₁ h₂).resolve_left h₃
@@ -338,7 +338,7 @@ theorem eq_norm {α} [IntModule α] (ctx : Context α) (lhs rhs : Expr) (p : Pol
: norm_cert lhs rhs p lhs.denote ctx = rhs.denote ctx p.denote' ctx = 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
theorem le_of_eq {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem le_of_eq {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: norm_cert lhs rhs p lhs.denote ctx = rhs.denote ctx p.denote' ctx 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote, h₁, sub_self]
apply Preorder.le_refl
@@ -351,21 +351,21 @@ theorem diseq_norm {α} [IntModule α] (ctx : Context α) (lhs rhs : Expr) (p :
rw [add_left_comm, sub_eq_add_neg, sub_self, add_zero] at h
contradiction
theorem le_norm {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem le_norm {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: norm_cert lhs rhs p lhs.denote ctx rhs.denote ctx p.denote' ctx 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote]
replace h₁ := add_le_left h₁ (-rhs.denote ctx)
simp [ sub_eq_add_neg, sub_self] at h₁
assumption
theorem lt_norm {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem lt_norm {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: norm_cert lhs rhs p lhs.denote ctx < rhs.denote ctx p.denote' ctx < 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote]
replace h₁ := add_lt_left h₁ (-rhs.denote ctx)
simp [ sub_eq_add_neg, sub_self] at h₁
assumption
theorem not_le_norm {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_le_norm {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: norm_cert rhs lhs p ¬ lhs.denote ctx rhs.denote ctx p.denote' ctx < 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote]
replace h₁ := LinearOrder.lt_of_not_le h₁
@@ -373,7 +373,7 @@ theorem not_le_norm {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [Ordere
simp [ sub_eq_add_neg, sub_self] at h₁
assumption
theorem not_lt_norm {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_lt_norm {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: norm_cert rhs lhs p ¬ lhs.denote ctx < rhs.denote ctx p.denote' ctx 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote]
replace h₁ := LinearOrder.le_of_not_lt h₁
@@ -383,14 +383,14 @@ theorem not_lt_norm {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [Ordere
-- If the module does not have a linear order, we can still put the expressions in polynomial forms
theorem not_le_norm' {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_le_norm' {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: norm_cert lhs rhs p ¬ lhs.denote ctx rhs.denote ctx ¬ p.denote' ctx 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote]; intro h
replace h := add_le_right (rhs.denote ctx) h
rw [sub_eq_add_neg, add_left_comm, sub_eq_add_neg, sub_self] at h; simp at h
contradiction
theorem not_lt_norm' {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_lt_norm' {α} [IntModule α] [Preorder α] [OrderedAdd α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: norm_cert lhs rhs p ¬ lhs.denote ctx < rhs.denote ctx ¬ p.denote' ctx < 0 := by
simp [norm_cert]; intro _ h₁; subst p; simp [Expr.denote]; intro h
replace h := add_lt_right (rhs.denote ctx) h
@@ -403,7 +403,7 @@ Equality detection
def eq_of_le_ge_cert (p₁ p₂ : Poly) : Bool :=
p₂ == p₁.mul (-1)
theorem eq_of_le_ge {α} [IntModule α] [LE α] [LT α] [PartialOrder α] [OrderedAdd α] (ctx : Context α) (p₁ : Poly) (p₂ : Poly)
theorem eq_of_le_ge {α} [IntModule α] [PartialOrder α] [OrderedAdd α] (ctx : Context α) (p₁ : Poly) (p₂ : Poly)
: eq_of_le_ge_cert p₁ p₂ p₁.denote' ctx 0 p₂.denote' ctx 0 p₁.denote' ctx = 0 := by
simp [eq_of_le_ge_cert]
intro; subst p₂; simp
@@ -419,7 +419,7 @@ Helper theorems for closing the goal
theorem diseq_unsat {α} [IntModule α] (ctx : Context α) : (Poly.nil).denote ctx 0 False := by
simp [Poly.denote]
theorem lt_unsat {α} [IntModule α] [LE α] [LT α] [Preorder α] (ctx : Context α) : (Poly.nil).denote ctx < 0 False := by
theorem lt_unsat {α} [IntModule α] [Preorder α] (ctx : Context α) : (Poly.nil).denote ctx < 0 False := by
simp [Poly.denote]; intro h
have := Preorder.lt_iff_le_not_le.mp h
simp at this
@@ -427,7 +427,7 @@ theorem lt_unsat {α} [IntModule α] [LE α] [LT α] [Preorder α] (ctx : Contex
def zero_lt_one_cert (p : Poly) : Bool :=
p == .add (-1) 0 .nil
theorem zero_lt_one {α} [Ring α] [LE α] [LT α] [Preorder α] [OrderedRing α] (ctx : Context α) (p : Poly)
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]
rw [neg_lt_iff, neg_zero]; apply OrderedRing.zero_lt_one
@@ -435,7 +435,7 @@ theorem zero_lt_one {α} [Ring α] [LE α] [LT α] [Preorder α] [OrderedRing α
def zero_ne_one_cert (p : Poly) : Bool :=
p == .add 1 0 .nil
theorem zero_ne_one_of_ord_ring {α} [Ring α] [LE α] [LT α] [Preorder α] [OrderedRing α] (ctx : Context α) (p : Poly)
theorem zero_ne_one_of_ord_ring {α} [Ring α] [Preorder α] [OrderedRing α] (ctx : Context α) (p : Poly)
: zero_ne_one_cert p (0 : Var).denote ctx = One.one p.denote' ctx 0 := by
simp [zero_ne_one_cert]; intro _ h; subst p; simp [Poly.denote, h, One.one]
intro h; have := OrderedRing.zero_lt_one (R := α); simp [h, Preorder.lt_irrefl] at this
@@ -484,7 +484,7 @@ theorem eq_coeff {α} [IntModule α] [NoNatZeroDivisors α] (ctx : Context α) (
def coeff_cert (p₁ p₂ : Poly) (k : Nat) :=
k > 0 && p₁ == p₂.mul k
theorem le_coeff {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
theorem le_coeff {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
: coeff_cert p₁ p₂ k p₁.denote' ctx 0 p₂.denote' ctx 0 := by
simp [coeff_cert]; intro h _; subst p₁; simp
have : k > (0 : Int) := Int.natCast_pos.mpr h
@@ -493,7 +493,7 @@ theorem le_coeff {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [OrderedAd
replace h₂ := zsmul_pos_iff (k) h₂ |>.mpr this
exact Preorder.lt_irrefl 0 (Preorder.lt_of_lt_of_le h₂ h₁)
theorem lt_coeff {α} [IntModule α] [LE α] [LT α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
theorem lt_coeff {α} [IntModule α] [LinearOrder α] [OrderedAdd α] (ctx : Context α) (p₁ p₂ : Poly) (k : Nat)
: coeff_cert p₁ p₂ k p₁.denote' ctx < 0 p₂.denote' ctx < 0 := by
simp [coeff_cert]; intro h _; subst p₁; simp
have : k > (0 : Int) := Int.natCast_pos.mpr h
@@ -544,7 +544,7 @@ def eq_le_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
let b := p₂.coeff x
a 0 && p₃ == (p₂.mul a |>.combine (p₁.mul (-b)))
theorem eq_le_subst {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (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₂
@@ -554,7 +554,7 @@ def eq_lt_subst_cert (x : Var) (p₁ p₂ p₃ : Poly) :=
let b := p₂.coeff x
a > 0 && p₃ == (p₂.mul a |>.combine (p₁.mul (-b)))
theorem eq_lt_subst {α} [IntModule α] [LE α] [LT α] [Preorder α] [OrderedAdd α] (ctx : Context α) (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

View File

@@ -17,7 +17,7 @@ namespace Lean.Grind
/--
Addition is compatible with a preorder if `a ≤ b ↔ a + c ≤ b + c`.
-/
class OrderedAdd (M : Type u) [HAdd M M M] [LE M] [LT M] [Preorder M] where
class OrderedAdd (M : Type u) [HAdd M M M] [Preorder M] where
/-- `a + c ≤ b + c` iff `a ≤ b`. -/
add_le_left_iff : {a b : M} (c : M), a b a + c b + c
@@ -30,7 +30,7 @@ open AddCommMonoid NatModule
section
variable {M : Type u} [LE M] [LT M] [Preorder M] [AddCommMonoid M] [OrderedAdd M]
variable {M : Type u} [Preorder M] [AddCommMonoid 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]
@@ -73,7 +73,7 @@ end
section
variable {M : Type u} [LE M] [LT M] [Preorder M] [NatModule M] [OrderedAdd M]
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
@@ -117,7 +117,7 @@ end
section
open AddCommGroup
variable {M : Type u} [LE M] [LT M] [Preorder M] [AddCommGroup M] [OrderedAdd M]
variable {M : Type u} [Preorder M] [AddCommGroup 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]
@@ -127,7 +127,7 @@ theorem neg_le_iff {a b : M} : -a ≤ b ↔ -b ≤ a := by
end
section
variable {M : Type u} [LE M] [LT M] [Preorder M] [IntModule M] [OrderedAdd M]
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 :=
@@ -154,7 +154,7 @@ theorem zsmul_nonneg {k : Int} {x : M} (h : 0 ≤ k) (hx : 0 ≤ x) : 0 ≤ k *
end
section
variable {M : Type u} [LE M] [LT M] [Preorder M] [AddCommGroup M] [OrderedAdd M]
variable {M : Type u} [Preorder M] [AddCommGroup M] [OrderedAdd M]
open AddCommGroup
@@ -186,7 +186,7 @@ end
section
variable {M : Type u} [LE M] [LT M] [Preorder M] [IntModule M] [OrderedAdd M]
variable {M : Type u} [Preorder M] [IntModule M] [OrderedAdd M]
open IntModule
theorem zsmul_neg_iff (k : Int) {a : M} (h : a < 0) : k * a < 0 0 < k := by

View File

@@ -13,17 +13,18 @@ public section
namespace Lean.Grind
/-- A preorder is a reflexive, transitive relation `≤` with `a < b` defined in the obvious way. -/
class Preorder (α : Type u) [LE α] [LT α] where
class Preorder (α : Type u) extends LE α, LT α where
/-- The less-than-or-equal relation is reflexive. -/
le_refl : a : α, a a
/-- The less-than-or-equal relation is transitive. -/
le_trans : {a b c : α}, a b b c a c
lt := fun a b => a b ¬b a
/-- The less-than relation is determined by the less-than-or-equal relation. -/
lt_iff_le_not_le : {a b : α}, a < b a b ¬b a := by intros; rfl
namespace Preorder
variable {α : Type u} [LE α] [LT α] [Preorder α]
variable {α : Type u} [Preorder α]
theorem le_of_lt {a b : α} (h : a < b) : a b := (lt_iff_le_not_le.mp h).1
@@ -57,13 +58,13 @@ theorem not_gt_of_lt {a b : α} (h : a < b) : ¬a > b :=
end Preorder
/-- A partial order is a preorder with the additional property that `a ≤ b` and `b ≤ a` implies `a = b`. -/
class PartialOrder (α : Type u) [LE α] [LT α] extends Preorder α where
class PartialOrder (α : Type u) extends Preorder α where
/-- The less-than-or-equal relation is antisymmetric. -/
le_antisymm : {a b : α}, a b b a a = b
namespace PartialOrder
variable {α : Type u} [LE α] [LT α] [PartialOrder α]
variable {α : Type u} [PartialOrder α]
theorem le_iff_lt_or_eq {a b : α} : a b a < b a = b := by
constructor
@@ -78,13 +79,13 @@ theorem le_iff_lt_or_eq {a b : α} : a ≤ b ↔ a < b a = b := by
end PartialOrder
/-- A linear order is a partial order with the additional property that every pair of elements is comparable. -/
class LinearOrder (α : Type u) [LE α] [LT α] extends PartialOrder α where
class LinearOrder (α : Type u) extends PartialOrder α where
/-- For every two elements `a` and `b`, either `a ≤ b` or `b ≤ a`. -/
le_total : a b : α, a b b a
namespace LinearOrder
variable {α : Type u} [LE α] [LT α] [LinearOrder α]
variable {α : Type u} [LinearOrder α]
theorem trichotomy (a b : α) : a < b a = b b < a := by
cases LinearOrder.le_total a b with
@@ -99,12 +100,12 @@ theorem trichotomy (a b : α) : a < b a = b b < a := by
| inl h => right; right; exact h
| inr h => right; left; exact h.symm
theorem le_of_not_lt {a b : α} (h : ¬ a < b) : b a := by
theorem le_of_not_lt {α} [LinearOrder α] {a b : α} (h : ¬ a < b) : b a := by
cases LinearOrder.trichotomy a b
next => contradiction
next h => apply PartialOrder.le_iff_lt_or_eq.mpr; cases h <;> simp [*]
theorem lt_of_not_le {a b : α} (h : ¬ a b) : b < a := by
theorem lt_of_not_le {α} [LinearOrder α] {a b : α} (h : ¬ a b) : b < a := by
cases LinearOrder.trichotomy a b
next h₁ h₂ => have := Preorder.lt_iff_le_not_le.mp h₂; simp [h] at this
next h =>

View File

@@ -17,7 +17,7 @@ namespace Lean.Grind
A ring which is also equipped with a preorder is considered a strict ordered ring if addition, negation,
and multiplication are compatible with the preorder, and `0 < 1`.
-/
class OrderedRing (R : Type u) [Semiring R] [LE R] [LT R] [Preorder R] extends OrderedAdd R where
class OrderedRing (R : Type u) [Semiring R] [Preorder R] extends OrderedAdd R where
/-- In a strict ordered semiring, we have `0 < 1`. -/
zero_lt_one : (0 : R) < 1
/-- In a strict ordered semiring, we can multiply an inequality `a < b` on the left
@@ -33,7 +33,7 @@ variable {R : Type u} [Ring R]
section Preorder
variable [LE R] [LT R] [Preorder R] [OrderedRing R]
variable [Preorder R] [OrderedRing R]
theorem neg_one_lt_zero : (-1 : R) < 0 := by
have h := zero_lt_one (R := R)
@@ -52,7 +52,7 @@ theorem ofNat_nonneg (x : Nat) : (OfNat.ofNat x : R) ≥ 0 := by
have := Preorder.lt_of_lt_of_le this ih
exact Preorder.le_of_lt this
instance [Ring R] [LE R] [LT R] [Preorder R] [OrderedRing R] : IsCharP R 0 := IsCharP.mk' _ _ <| by
instance [Ring α] [Preorder α] [OrderedRing α] : IsCharP α 0 := IsCharP.mk' _ _ <| by
intro x
simp only [Nat.mod_zero]; constructor
next =>
@@ -64,11 +64,11 @@ instance [Ring R] [LE R] [LT R] [Preorder R] [OrderedRing R] : IsCharP R 0 := Is
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
have h₁ : (OfNat.ofNat x : R) < 0 := by
have := OrderedRing.neg_one_lt_zero (R := R)
have h₁ : (OfNat.ofNat x : α) < 0 := by
have := OrderedRing.neg_one_lt_zero (R := α)
rw [h]; assumption
have h₂ := OrderedRing.ofNat_nonneg (R := R) x
have : (0 : R) < 0 := Preorder.lt_of_le_of_lt h₂ h₁
have h₂ := OrderedRing.ofNat_nonneg (R := α) x
have : (0 : α) < 0 := Preorder.lt_of_le_of_lt h₂ h₁
simp
exact (Preorder.lt_irrefl 0) this
next => intro h; rw [OfNat.ofNat, h]; rfl
@@ -77,7 +77,7 @@ end Preorder
section PartialOrder
variable [LE R] [LT R] [PartialOrder R] [OrderedRing R]
variable [PartialOrder R] [OrderedRing R]
theorem zero_le_one : (0 : R) 1 := Preorder.le_of_lt zero_lt_one
@@ -158,7 +158,7 @@ end PartialOrder
section LinearOrder
variable [LE R] [LT R] [LinearOrder R] [OrderedRing R]
variable [LinearOrder R] [OrderedRing R]
theorem mul_nonneg_iff {a b : R} : 0 a * b 0 a 0 b a 0 b 0 := by
rcases LinearOrder.trichotomy 0 a with (ha | rfl | ha)

View File

@@ -8,7 +8,6 @@ module
prelude
public import Init.Data.Zero
public import Init.Data.Int.DivMod.Lemmas
public import Init.Data.Int.LemmasAux
public import Init.Data.Int.Pow
public import Init.TacticsExtra
public import Init.Grind.Module.Basic
@@ -148,9 +147,6 @@ open NatModule
variable {α : Type u} [Semiring α]
theorem natCast_eq_ofNat (n : Nat) : NatCast.natCast n = OfNat.ofNat (α := α) n := by
rw [ofNat_eq_natCast]
theorem natCast_zero : ((0 : Nat) : α) = 0 := by
rw [ ofNat_eq_natCast 0]
theorem natCast_one : ((1 : Nat) : α) = 1 := (ofNat_eq_natCast 1).symm
@@ -224,21 +220,6 @@ theorem intCast_negSucc (n : Nat) : ((-(n + 1) : Int) : α) = -((n : α) + 1) :=
rw [intCast_neg, Int.natCast_add_one, intCast_natCast, ofNat_eq_natCast, natCast_add]
theorem intCast_nat_add {x y : Nat} : ((x + y : Int) : α) = ((x : α) + (y : α)) := by
rw [Int.ofNat_add_ofNat, intCast_natCast, natCast_add]
theorem intCast_eq_ofNat_of_nonneg (x : Int) (h : Int.ble' 0 x) : IntCast.intCast (R := α) x = OfNat.ofNat (α := α) x.toNat := by
show Int.cast x = _
rw [Int.ble'_eq_true] at h
have := Int.toNat_of_nonneg h
conv => lhs; rw [ this, Ring.intCast_natCast]
rw [Semiring.ofNat_eq_natCast]
theorem intCast_eq_ofNat_of_nonpos (x : Int) (h : Int.ble' x 0) : IntCast.intCast (R := α) x = - OfNat.ofNat (α := α) x.natAbs := by
show Int.cast x = _
rw [Int.ble'_eq_true] at h
have := Int.eq_neg_natAbs_of_nonpos h
conv => lhs; rw [this]
rw [Ring.intCast_neg, Semiring.ofNat_eq_natCast, Ring.intCast_natCast]
theorem intCast_nat_sub {x y : Nat} (h : x y) : (((x - y : Nat) : Int) : α) = ((x : α) - (y : α)) := by
induction x with
| zero =>

View File

@@ -359,7 +359,7 @@ instance {p} [Semiring α] [AddRightCancel α] [IsCharP α p] : IsCharP (OfSemir
apply Quot.sound
exists 0; simp [ Semiring.ofNat_eq_natCast, this]
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : LE (OfSemiring.Q α) where
instance [Preorder α] [OrderedAdd α] : LE (OfSemiring.Q α) where
le a b := Q.liftOn₂ a b (fun (a, b) (c, d) => a + d b + c)
(by intro (a₁, b₁) (a₂, b₂) (a₃, b₃) (a₄, b₄)
simp; intro k₁ h₁ k₂ h₂
@@ -375,14 +375,11 @@ instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : LE (OfSemiring.Q α) wh
rw [this]; clear this
rw [ OrderedAdd.add_le_left_iff])
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : LT (OfSemiring.Q α) where
lt a b := a b ¬b a
@[local simp] theorem mk_le_mk [LE α] [LT α] [Preorder α] [OrderedAdd α] {a₁ a₂ b₁ b₂ : α} :
@[local simp] theorem mk_le_mk [Preorder α] [OrderedAdd α] {a₁ a₂ b₁ b₂ : α} :
Q.mk (a₁, a₂) Q.mk (b₁, b₂) a₁ + b₂ a₂ + b₁ := by
rfl
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : Preorder (OfSemiring.Q α) where
instance [Preorder α] [OrderedAdd α] : Preorder (OfSemiring.Q α) where
le_refl a := by
obtain a₁, a₂ := a
change Q.mk _ Q.mk _
@@ -401,23 +398,23 @@ instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : Preorder (OfSemiring.Q
rw [this]; clear this
exact OrderedAdd.add_le_add h₁ h₂
@[local simp] private theorem mk_lt_mk [LE α] [LT α] [Preorder α] [OrderedAdd α] {a₁ a₂ b₁ b₂ : α} :
@[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, Semiring.add_comm]
@[local simp] private theorem mk_pos [LE α] [LT α] [Preorder α] [OrderedAdd α] {a₁ a₂ : α} :
@[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]
@[local simp]
theorem toQ_le [LE α] [LT α] [Preorder α] [OrderedAdd α] {a b : α} : toQ a toQ b a b := by
theorem toQ_le [Preorder α] [OrderedAdd α] {a b : α} : toQ a toQ b a b := by
simp
@[local simp]
theorem toQ_lt [LE α] [LT α] [Preorder α] [OrderedAdd α] {a b : α} : toQ a < toQ b a < b := by
theorem toQ_lt [Preorder α] [OrderedAdd α] {a b : α} : toQ a < toQ b a < b := by
simp [Preorder.lt_iff_le_not_le]
instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : OrderedAdd (OfSemiring.Q α) where
instance [Preorder α] [OrderedAdd α] : OrderedAdd (OfSemiring.Q α) where
add_le_left_iff := by
intro a b c
obtain a₁, a₂ := a
@@ -431,7 +428,7 @@ instance [LE α] [LT α] [Preorder α] [OrderedAdd α] : OrderedAdd (OfSemiring.
rw [ OrderedAdd.add_le_left_iff]
-- This perhaps works in more generality than `ExistsAddOfLT`?
instance [LE α] [LT α] [Preorder α] [OrderedRing α] [ExistsAddOfLT α] : OrderedRing (OfSemiring.Q α) where
instance [Preorder α] [OrderedRing α] [ExistsAddOfLT α] : OrderedRing (OfSemiring.Q α) where
zero_lt_one := by
rw [ toQ_ofNat, toQ_ofNat, toQ_lt]
exact OrderedRing.zero_lt_one

View File

@@ -1616,21 +1616,21 @@ theorem diseq_norm {α} [CommRing α] (ctx : Context α) (lhs rhs : Expr) (p : P
open OrderedAdd
theorem le_norm {α} [CommRing α] [LE α] [LT α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem le_norm {α} [CommRing α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: core_cert lhs rhs p lhs.denote ctx rhs.denote ctx p.denoteAsIntModule ctx 0 := by
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
replace h := add_le_left h ((-1) * rhs.denote ctx)
rw [neg_mul, sub_eq_add_neg, one_mul, sub_eq_add_neg, sub_self] at h
assumption
theorem lt_norm {α} [CommRing α] [LE α] [LT α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem lt_norm {α} [CommRing α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: core_cert lhs rhs p lhs.denote ctx < rhs.denote ctx p.denoteAsIntModule ctx < 0 := by
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h; subst p; simp [Expr.denote_toPoly, Expr.denote]
replace h := add_lt_left h ((-1) * rhs.denote ctx)
rw [neg_mul, sub_eq_add_neg, one_mul, sub_eq_add_neg, sub_self] at h
assumption
theorem not_le_norm {α} [CommRing α] [LE α] [LT α] [LinearOrder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_le_norm {α} [CommRing α] [LinearOrder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: core_cert rhs lhs p ¬ lhs.denote ctx rhs.denote ctx p.denoteAsIntModule ctx < 0 := by
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]
replace h₁ := LinearOrder.lt_of_not_le h₁
@@ -1638,7 +1638,7 @@ theorem not_le_norm {α} [CommRing α] [LE α] [LT α] [LinearOrder α] [Ordered
simp [ sub_eq_add_neg, sub_self] at h₁
assumption
theorem not_lt_norm {α} [CommRing α] [LE α] [LT α] [LinearOrder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_lt_norm {α} [CommRing α] [LinearOrder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: core_cert rhs lhs p ¬ lhs.denote ctx < rhs.denote ctx p.denoteAsIntModule ctx 0 := by
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]
replace h₁ := LinearOrder.le_of_not_lt h₁
@@ -1646,14 +1646,14 @@ theorem not_lt_norm {α} [CommRing α] [LE α] [LT α] [LinearOrder α] [Ordered
simp [ sub_eq_add_neg, sub_self] at h₁
assumption
theorem not_le_norm' {α} [CommRing α] [LE α] [LT α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_le_norm' {α} [CommRing α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: core_cert lhs rhs p ¬ lhs.denote ctx rhs.denote ctx ¬ p.denoteAsIntModule ctx 0 := by
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]; intro h
replace h : rhs.denote ctx + (lhs.denote ctx - rhs.denote ctx) _ := add_le_right (rhs.denote ctx) h
rw [sub_eq_add_neg, add_left_comm, sub_eq_add_neg, sub_self] at h; simp [add_zero] at h
contradiction
theorem not_lt_norm' {α} [CommRing α] [LE α] [LT α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
theorem not_lt_norm' {α} [CommRing α] [Preorder α] [OrderedRing α] (ctx : Context α) (lhs rhs : Expr) (p : Poly)
: core_cert lhs rhs p ¬ lhs.denote ctx < rhs.denote ctx ¬ p.denoteAsIntModule ctx < 0 := by
simp [core_cert, Poly.denoteAsIntModule_eq_denote]; intro _ h₁; subst p; simp [Expr.denote_toPoly, Expr.denote]; intro h
replace h : rhs.denote ctx + (lhs.denote ctx - rhs.denote ctx) < _ := add_lt_right (rhs.denote ctx) h

View File

@@ -102,6 +102,11 @@ structure Config where
ring := true
ringSteps := 10000
/--
When `true` (default: `false`), the commutative ring procedure in `grind` constructs stepwise
proof terms, instead of a single-step Nullstellensatz certificate
-/
ringNull := false
/--
When `true` (default: `true`), uses procedure for handling linear arithmetic for `IntModule`, and
`CommRing`.
-/

View File

@@ -7,7 +7,6 @@ module
prelude
public import Init.Grind.Ring.Basic
public import Init.Grind.Ordered.Order
public import Init.GrindInstances.ToInt
public import all Init.Data.BitVec.Basic
public import all Init.Grind.ToInt
@@ -54,15 +53,4 @@ example : ToInt.Sub (BitVec w) (.uint w) := inferInstance
instance : ToInt.Pow (BitVec w) (.uint w) :=
ToInt.pow_of_semiring (by simp)
instance : Preorder (BitVec w) where
le_refl := BitVec.le_refl
le_trans := BitVec.le_trans
lt_iff_le_not_le {a b} := Std.LawfulOrderLT.lt_iff a b
instance : PartialOrder (BitVec w) where
le_antisymm := BitVec.le_antisymm
instance : LinearOrder (BitVec w) where
le_total := BitVec.le_total
end Lean.Grind

View File

@@ -274,18 +274,13 @@ structure Config where
-/
letToHave : Bool := true
/--
When `true` (default: `true`), `simp` tries to realize constant `f.congr_simp`
When `true` (default : `true`), `simp` tries to realize constant `f.congr_simp`
when constructing an auxiliary congruence proof for `f`.
This option exists because the termination prover uses `simp` and `withoutModifyingEnv`
while constructing the termination proof. Thus, any constant realized by `simp`
is deleted.
-/
congrConsts : Bool := true
/--
When `true` (default: `true`), the bitvector simprocs use `BitVec.ofNat` for representing
bitvector literals.
-/
bitVecOfNat : Bool := true
deriving Inhabited, BEq
-- Configuration object for `simp_all`

View File

@@ -77,11 +77,7 @@ macro_rules
for (c₁, c₂) in cs₁.zip cs₂ |>.reverse do
body `($c₁ = $c₂ $body)
let hint : Ident `(hint)
match kind with
| `(attrKind| local) =>
`($[$doc?:docComment]? @[$kind unification_hint] private def $(n.getD hint) $bs* : Sort _ := $body)
| _ =>
`($[$doc?:docComment]? @[$kind unification_hint, expose] public def $(n.getD hint) $bs* : Sort _ := $body)
`($[$doc?:docComment]? @[$kind unification_hint, expose] def $(n.getD hint) $bs* : Sort _ := $body)
end Lean
open Lean

View File

@@ -3030,15 +3030,6 @@ internal detail that's not observable by Lean code.
def Array.size {α : Type u} (a : @& Array α) : Nat :=
a.toList.length
/--
Version of `Array.getInternal` that does not increment the reference count of its result.
This is only intended for direct use by the compiler.
-/
@[extern "lean_array_fget_borrowed"]
unsafe opaque Array.getInternalBorrowed {α : Type u} (a : @& Array α) (i : @& Nat) (h : LT.lt i a.size) : α :=
a.toList.get i, h
/--
Use the indexing notation `a[i]` instead.
@@ -3068,14 +3059,6 @@ Examples:
@[inline] abbrev Array.getD (a : Array α) (i : Nat) (v₀ : α) : α :=
dite (LT.lt i a.size) (fun h => a.getInternal i h) (fun _ => v₀)
/--
Version of `Array.get!Internal` that does not increment the reference count of its result.
This is only intended for direct use by the compiler.
-/
@[extern "lean_array_get_borrowed"]
unsafe opaque Array.get!InternalBorrowed {α : Type u} [Inhabited α] (a : @& Array α) (i : @& Nat) : α
/--
Use the indexing notation `a[i]!` instead.

View File

@@ -2128,7 +2128,7 @@ macro (name := mintroMacro) (priority:=low) "mintro" : tactic =>
`mspec` is an `apply`-like tactic that applies a Hoare triple specification to the target of the
stateful goal.
Given a stateful goal `H ⊢ₛ wp⟦prog⟧ Q'`, `mspec foo_spec` will instantiate
Given a stateful goal `H ⊢ₛ wp⟦prog⟧.apply Q'`, `mspec foo_spec` will instantiate
`foo_spec : ... → ⦃P⦄ foo ⦃Q⦄`, match `foo` against `prog` and produce subgoals for
the verification conditions `?pre : H ⊢ₛ P` and `?post : Q ⊢ₚ Q'`.
@@ -2137,12 +2137,11 @@ the verification conditions `?pre : H ⊢ₛ P` and `?post : Q ⊢ₚ Q'`.
* If `?pre` or `?post` follow by `.rfl`, then they are discharged automatically.
* `?post` is automatically simplified into constituent `⊢ₛ` entailments on
success and failure continuations.
* `?pre` and `?post.*` goals introduce their stateful hypothesis under an inaccessible name.
You can give it a name with the `mrename_i` tactic.
* `?pre` and `?post.*` goals introduce their stateful hypothesis as `h`.
* Any uninstantiated MVar arising from instantiation of `foo_spec` becomes a new subgoal.
* If the target of the stateful goal looks like `fun s => _` then `mspec` will first `mintro ∀s`.
* If `P` has schematic variables that can be instantiated by doing `mintro ∀s`, for example
`foo_spec : ∀(n:Nat), ⦃fun s => ⌜n = s⌝⦄ foo ⦃Q⦄`, then `mspec` will do `mintro ∀s` first to
`foo_spec : ∀(n:Nat), ⦃⌜n = Nat⌝⦄ foo ⦃Q⦄`, then `mspec` will do `mintro ∀s` first to
instantiate `n = s`.
* Right before applying the spec, the `mframe` tactic is used, which has the following effect:
Any hypothesis `Hᵢ` in the goal `h₁:H₁, h₂:H₂, ..., hₙ:Hₙ ⊢ₛ T` that is

View File

@@ -126,10 +126,8 @@ def addDecl (decl : Declaration) : CoreM Unit := do
let cancelTk IO.CancelToken.new
let checkAct Core.wrapAsyncAsSnapshot (cancelTk? := cancelTk) fun _ => doAddAndCommit
let t BaseIO.mapTask checkAct env.checked
-- Do not display reporting range; most uses of `addDecl` are for registering auxiliary decls
-- users should not worry about and other callers can add a separate task with ranges
-- themselves, see `MutualDef`.
Core.logSnapshotTask { stx? := none, reportingRange := .skip, task := t, cancelTk? := cancelTk }
let endRange? := ( getRef).getTailPos?.map fun pos => pos, pos
Core.logSnapshotTask { stx? := none, reportingRange? := endRange?, task := t, cancelTk? := cancelTk }
else
try
doAddAndCommit

View File

@@ -46,8 +46,8 @@ abbrev ParamMap := Std.HashMap Key (Array Param)
def ParamMap.fmt (map : ParamMap) : Format :=
let fmts := map.fold (fun fmt k ps =>
let k := match k with
| .decl n => format n
| .jp n id => format n ++ ":" ++ format id
| ParamMap.Key.decl n => format n
| ParamMap.Key.jp n id => format n ++ ":" ++ format id
fmt ++ Format.line ++ k ++ " -> " ++ formatParams ps)
Format.nil
"{" ++ (Format.nest 1 fmts) ++ "}"
@@ -70,42 +70,41 @@ def initBorrow (ps : Array Param) : Array Param :=
def initBorrowIfNotExported (exported : Bool) (ps : Array Param) : Array Param :=
if exported then ps else initBorrow ps
partial def visitFnBody (fnid : FunId) (b : FnBody) : StateM ParamMap Unit := do
match b with
| .jdecl j xs v b =>
modify fun m => m.insert (.jp fnid j) (initBorrow xs)
partial def visitFnBody (fnid : FunId) : FnBody StateM ParamMap Unit
| FnBody.jdecl j xs v b => do
modify fun m => m.insert (ParamMap.Key.jp fnid j) (initBorrow xs)
visitFnBody fnid v
visitFnBody fnid b
| .case _ _ _ alts => alts.forM fun alt => visitFnBody fnid alt.body
| _ => do
unless b.isTerminal do
visitFnBody fnid b.body
| FnBody.case _ _ _ alts => alts.forM fun alt => visitFnBody fnid alt.body
| e => do
unless e.isTerminal do
visitFnBody fnid e.body
def visitDecls (env : Environment) (decls : Array Decl) : StateM ParamMap Unit :=
decls.forM fun decl => match decl with
| .fdecl (f := f) (xs := xs) (body := b) .. => do
let exported := isExport env f
modify fun m => m.insert (.decl f) (initBorrowIfNotExported exported xs)
modify fun m => m.insert (ParamMap.Key.decl f) (initBorrowIfNotExported exported xs)
visitFnBody f b
| _ => pure ()
end InitParamMap
def mkInitParamMap (env : Environment) (decls : Array Decl) : ParamMap :=
(InitParamMap.visitDecls env decls *> get).run' {}
(InitParamMap.visitDecls env decls *> get).run' {}
/-! Apply the inferred borrow annotations stored at `ParamMap` to a block of mutually
recursive functions. -/
namespace ApplyParamMap
partial def visitFnBody (fn : FunId) (paramMap : ParamMap) : FnBody FnBody
| .jdecl j _ v b =>
| FnBody.jdecl j _ v b =>
let v := visitFnBody fn paramMap v
let b := visitFnBody fn paramMap b
match paramMap[Key.jp fn j]? with
| some ys => .jdecl j ys v b
match paramMap[ParamMap.Key.jp fn j]? with
| some ys => FnBody.jdecl j ys v b
| none => unreachable!
| .case tid x xType alts =>
.case tid x xType <| alts.map fun alt => alt.modifyBody (visitFnBody fn paramMap)
| FnBody.case tid x xType alts =>
FnBody.case tid x xType <| alts.map fun alt => alt.modifyBody (visitFnBody fn paramMap)
| e =>
if e.isTerminal then e
else
@@ -115,10 +114,10 @@ partial def visitFnBody (fn : FunId) (paramMap : ParamMap) : FnBody → FnBody
def visitDecls (decls : Array Decl) (paramMap : ParamMap) : Array Decl :=
decls.map fun decl => match decl with
| .fdecl f _ ty b info =>
| Decl.fdecl f _ ty b info =>
let b := visitFnBody f paramMap b
match paramMap[Key.decl f]? with
| some xs => .fdecl f xs ty b info
match paramMap[ParamMap.Key.decl f]? with
| some xs => Decl.fdecl f xs ty b info
| none => unreachable!
| other => other
@@ -188,7 +187,7 @@ def getParamInfo (k : ParamMap.Key) : M (Array Param) := do
| some ps => pure ps
| none =>
match k with
| .decl fn => do
| ParamMap.Key.decl fn => do
let ctx read
match findEnvDecl ctx.env fn with
| some decl => pure decl.params
@@ -232,71 +231,53 @@ def ownArgsIfParam (xs : Array Arg) : M Unit := do
| .var x => if ctx.paramSet.contains x.idx then ownVar x
| .erased => pure ()
def collectExpr (z : VarId) (e : Expr) : M Unit := do
match e with
| .reset _ x =>
ownVar z
ownVar x
| .reuse x _ _ ys =>
ownVar z
ownVar x
ownArgsIfParam ys
| .ctor _ xs =>
ownVar z
ownArgsIfParam xs
| .proj _ x =>
def collectExpr (z : VarId) : Expr M Unit
| Expr.reset _ x => ownVar z *> ownVar x
| Expr.reuse x _ _ ys => ownVar z *> ownVar x *> ownArgsIfParam ys
| Expr.ctor _ xs => ownVar z *> ownArgsIfParam xs
| Expr.proj _ x => do
if ( isOwned x) then ownVar z
if ( isOwned z) then ownVar x
| .fap g xs =>
let ps getParamInfo (.decl g)
ownVar z
ownArgsUsingParams xs ps
| .ap x ys =>
ownVar z
ownVar x
ownArgs ys
| .pap _ xs =>
ownVar z
ownArgs xs
| _ => pure ()
| Expr.fap g xs => do
let ps getParamInfo (ParamMap.Key.decl g)
ownVar z *> ownArgsUsingParams xs ps
| Expr.ap x ys => ownVar z *> ownVar x *> ownArgs ys
| Expr.pap _ xs => ownVar z *> ownArgs xs
| _ => pure ()
def preserveTailCall (x : VarId) (v : Expr) (b : FnBody) : M Unit := do
let ctx read
match v, b with
| (.fap g ys), (.ret (.var z)) =>
| (Expr.fap g ys), (FnBody.ret (.var z)) =>
-- NOTE: we currently support TCO for self-calls only
if ctx.currFn == g && x == z then
let ps getParamInfo (.decl g)
let ps getParamInfo (ParamMap.Key.decl g)
ownParamsUsingArgs ys ps
| _, _ => pure ()
def updateParamSet (ctx : BorrowInfCtx) (ps : Array Param) : BorrowInfCtx :=
{ ctx with paramSet := ps.foldl (fun s p => s.insert p.x.idx) ctx.paramSet }
partial def collectFnBody (b : FnBody) : M Unit := do
match b with
| .jdecl j ys v b =>
partial def collectFnBody : FnBody M Unit
| FnBody.jdecl j ys v b => do
withReader (fun ctx => updateParamSet ctx ys) (collectFnBody v)
let ctx read
updateParamMap (.jp ctx.currFn j)
updateParamMap (ParamMap.Key.jp ctx.currFn j)
collectFnBody b
| .vdecl x _ v b =>
collectFnBody b
collectExpr x v
preserveTailCall x v b
| .jmp j ys =>
| FnBody.vdecl x _ v b => collectFnBody b *> collectExpr x v *> preserveTailCall x v b
| FnBody.jmp j ys => do
let ctx read
let ps getParamInfo (.jp ctx.currFn j)
let ps getParamInfo (ParamMap.Key.jp ctx.currFn j)
ownArgsUsingParams ys ps -- for making sure the join point can reuse
ownParamsUsingArgs ys ps -- for making sure the tail call is preserved
| .case _ _ _ alts => alts.forM fun alt => collectFnBody alt.body
| _ => do unless b.isTerminal do collectFnBody b.body
| FnBody.case _ _ _ alts => alts.forM fun alt => collectFnBody alt.body
| e => do unless e.isTerminal do collectFnBody e.body
partial def collectDecl : Decl M Unit
| .fdecl (f := f) (xs := ys) (body := b) .. =>
withReader (fun ctx => let ctx := updateParamSet ctx ys; { ctx with currFn := f }) do
collectFnBody b
updateParamMap (.decl f)
updateParamMap (ParamMap.Key.decl f)
| _ => pure ()
/-- Keep executing `x` until it reaches a fixpoint -/

View File

@@ -76,7 +76,7 @@ private partial def formatIRType : IRType → Format
let _ : ToFormat IRType := formatIRType
"union " ++ Format.bracket "{" (Format.joinSep tys.toList ", ") "}"
instance : ToFormat IRType := private_decl% formatIRType
instance : ToFormat IRType := formatIRType
instance : ToString IRType := toString format
private def formatParam : Param Format

View File

@@ -18,17 +18,17 @@ This transformation is applied before lower level optimizations
that introduce the instructions `release` and `set`
-/
structure DerivedValInfo where
structure VarProjInfo where
parent? : Option VarId
children : VarIdSet
deriving Inhabited
abbrev DerivedValMap := Std.HashMap VarId DerivedValInfo
abbrev VarProjMap := Std.HashMap VarId VarProjInfo
namespace CollectDerivedValInfo
namespace CollectProjInfo
structure State where
varMap : DerivedValMap := {}
varMap : VarProjMap := {}
borrowedParams : VarIdSet := {}
abbrev M := StateM State
@@ -45,39 +45,27 @@ private def visitParam (p : Param) : M Unit :=
else s.borrowedParams
}
private partial def addDerivedValue (parent : VarId) (child : VarId) : M Unit := do
modify fun s => { s with
varMap := s.varMap.modify parent fun info =>
{ info with children := info.children.insert child }
}
modify fun s => { s with
varMap := s.varMap.insert child {
parent? := some parent
children := {}
}
}
private partial def removeFromParent (child : VarId) : M Unit := do
if let some (some parent) := ( get).varMap.get? child |>.map (·.parent?) then
modify fun s => { s with
varMap := s.varMap.modify parent fun info =>
{ info with children := info.children.erase child }
}
private partial def visitFnBody (b : FnBody) : M Unit := do
match b with
| .vdecl x _ e b =>
match e with
| .proj _ parent =>
addDerivedValue parent x
| .fap ``Array.getInternal args =>
if let .var parent := args[1]! then
addDerivedValue parent x
| .fap ``Array.get!Internal args =>
if let .var parent := args[2]! then
addDerivedValue parent x
modify fun s => { s with
varMap := s.varMap.modify parent fun info =>
{ info with children := info.children.insert x }
}
modify fun s => { s with
varMap := s.varMap.insert x {
parent? := some parent
children := {}
}
}
| .reset _ x =>
removeFromParent x
if let some (some parent) := ( get).varMap.get? x |>.map (·.parent?) then
modify fun s => { s with
varMap := s.varMap.modify parent fun info =>
{ info with children := info.children.erase x }
}
| _ => pure ()
visitFnBody b
| .jdecl _ ps v b =>
@@ -87,15 +75,15 @@ private partial def visitFnBody (b : FnBody) : M Unit := do
| .case _ _ _ alts => alts.forM (visitFnBody ·.body)
| _ => if !b.isTerminal then visitFnBody b.body
private partial def collectDerivedValInfo (ps : Array Param) (b : FnBody)
: DerivedValMap × VarIdSet := Id.run do
private partial def collectProjInfo (ps : Array Param) (b : FnBody)
: VarProjMap × VarIdSet := Id.run do
let _, { varMap, borrowedParams } := go |>.run { }
return varMap, borrowedParams
where go : M Unit := do
ps.forM visitParam
visitFnBody b
end CollectDerivedValInfo
end CollectProjInfo
structure VarInfo where
isPossibleRef : Bool
@@ -122,7 +110,7 @@ structure Context where
env : Environment
decls : Array Decl
borrowedParams : VarIdSet
derivedValMap : DerivedValMap
varProjMap : VarProjMap
varMap : VarMap := {}
jpLiveVarMap : JPLiveVarMap := {} -- map: join point => live variables
localCtx : LocalContext := {} -- we use it to store the join point declarations
@@ -139,7 +127,7 @@ def getJPParams (ctx : Context) (j : JoinPointId) : Array Param :=
@[specialize]
private partial def addDescendants (ctx : Context) (x : VarId) (s : VarIdSet)
(shouldAdd : VarId Bool := fun _ => true) : VarIdSet :=
if let some info := ctx.derivedValMap.get? x then
if let some info := ctx.varProjMap.get? x then
info.children.foldl (init := s) fun s child =>
let s := if shouldAdd child then s.insert child else s
addDescendants ctx child s shouldAdd
@@ -357,13 +345,7 @@ private def processVDecl (ctx : Context) (z : VarId) (t : IRType) (v : Expr) (b
| .fap f ys =>
let ps := (getDecl ctx f).params
let b := addDecAfterFullApp ctx ys ps b bLiveVars
let v :=
if f == ``Array.getInternal && bLiveVars.borrows.contains z then
.fap ``Array.getInternalBorrowed ys
else if f == ``Array.get!Internal && bLiveVars.borrows.contains z then
.fap ``Array.get!InternalBorrowed ys
else v
let b := .vdecl z t v b
let b := .vdecl z t v b
addIncBefore ctx ys ps b bLiveVars
| .ap x ys =>
let ysx := ys.push (.var x) -- TODO: avoid temporary array allocation
@@ -454,8 +436,8 @@ partial def visitFnBody (b : FnBody) (ctx : Context) : FnBody × LiveVars :=
partial def visitDecl (env : Environment) (decls : Array Decl) (d : Decl) : Decl :=
match d with
| .fdecl (xs := xs) (body := b) .. =>
let derivedValMap, borrowedParams := CollectDerivedValInfo.collectDerivedValInfo xs b
let ctx := updateVarInfoWithParams { env, decls, borrowedParams, derivedValMap } xs
let varProjMap, borrowedParams := CollectProjInfo.collectProjInfo xs b
let ctx := updateVarInfoWithParams { env, decls, borrowedParams, varProjMap } xs
let b, bLiveVars := visitFnBody b ctx
let b, _ := addDecForDeadParams ctx xs b bLiveVars
d.updateBody! b

View File

@@ -77,9 +77,6 @@ builtin_initialize inlineAttrs : EnumAttributes InlineAttributeKind ←
if kind matches .macroInline then
unless ( isValidMacroInline declName) do
throwError "Cannot add `[macro_inline]` attribute to `{declName}`: This attribute does not support this kind of declaration; only non-recursive definitions are supported"
withExporting (isExporting := !isPrivateName declName) do
if !( getConstInfo declName).isDefinition then
throwError "invalid `[macro_inline]` attribute, '{declName}' must be an exposed definition"
def setInlineAttribute (env : Environment) (declName : Name) (kind : InlineAttributeKind) : Except String Environment :=
inlineAttrs.setValue env declName kind

View File

@@ -715,7 +715,7 @@ partial def Code.collectUsed (code : Code) (s : FVarIdHashSet := {}) : FVarIdHas
| .jmp fvarId args => collectArgs args <| s.insert fvarId
end
@[inline] def collectUsedAtExpr (s : FVarIdHashSet) (e : Expr) : FVarIdHashSet :=
abbrev collectUsedAtExpr (s : FVarIdHashSet) (e : Expr) : FVarIdHashSet :=
collectType e s
/--

View File

@@ -227,7 +227,7 @@ This function panics if the substitution is mapping `fvarId` to an expression th
That is, it is not a type (or type former), nor `lcErased`. Recall that a valid `FVarSubst` contains only
expressions that are free variables, `lcErased`, or type formers.
-/
partial def normFVarImp (s : FVarSubst) (fvarId : FVarId) (translator : Bool) : NormFVarResult :=
private partial def normFVarImp (s : FVarSubst) (fvarId : FVarId) (translator : Bool) : NormFVarResult :=
match s[fvarId]? with
| some (.fvar fvarId') =>
if translator then

View File

@@ -42,72 +42,18 @@ private def mkNewFVarId (fvarId : FVarId) : InternalizeM FVarId := do
addFVarSubst fvarId fvarId'
return fvarId'
private partial def internalizeExpr (e : Expr) : InternalizeM Expr :=
go e
where
goApp (e : Expr) : InternalizeM Expr := do
match e with
| .app f a => return e.updateApp! ( goApp f) ( go a)
| _ => go e
go (e : Expr) : InternalizeM Expr := do
if e.hasFVar then
match e with
| .fvar fvarId => match ( get)[fvarId]? with
| some (.fvar fvarId') =>
-- In LCNF, types can't depend on let-bound fvars.
if ( findParam? fvarId').isSome then
return .fvar fvarId'
else
return anyExpr
| some .erased => return erasedExpr
| some (.type e) | none => return e
| .lit .. | .const .. | .sort .. | .mvar .. | .bvar .. => return e
| .app f a => return e.updateApp! ( goApp f) ( go a) |>.headBeta
| .mdata _ b => return e.updateMData! ( go b)
| .proj _ _ b => return e.updateProj! ( go b)
| .forallE _ d b _ => return e.updateForallE! ( go d) ( go b)
| .lam _ d b _ => return e.updateLambdaE! ( go d) ( go b)
| .letE .. => unreachable!
else
return e
def internalizeParam (p : Param) : InternalizeM Param := do
let binderName refreshBinderName p.binderName
let type internalizeExpr p.type
let type normExpr p.type
let fvarId mkNewFVarId p.fvarId
let p := { p with binderName, fvarId, type }
modifyLCtx fun lctx => lctx.addParam p
return p
def internalizeArg (arg : Arg) : InternalizeM Arg := do
match arg with
| .fvar fvarId =>
match ( get)[fvarId]? with
| some arg'@(.fvar _) => return arg'
| some arg'@.erased | some arg'@(.type _) => return arg'
| none => return arg
| .type e => return arg.updateType! ( internalizeExpr e)
| .erased => return arg
def internalizeArgs (args : Array Arg) : InternalizeM (Array Arg) :=
args.mapM internalizeArg
private partial def internalizeLetValue (e : LetValue) : InternalizeM LetValue := do
match e with
| .erased | .lit .. => return e
| .proj _ _ fvarId => match ( normFVar fvarId) with
| .fvar fvarId' => return e.updateProj! fvarId'
| .erased => return .erased
| .const _ _ args => return e.updateArgs! ( internalizeArgs args)
| .fvar fvarId args => match ( normFVar fvarId) with
| .fvar fvarId' => return e.updateFVar! fvarId' ( internalizeArgs args)
| .erased => return .erased
def internalizeLetDecl (decl : LetDecl) : InternalizeM LetDecl := do
let binderName refreshBinderName decl.binderName
let type internalizeExpr decl.type
let value internalizeLetValue decl.value
let type normExpr decl.type
let value normLetValue decl.value
let fvarId mkNewFVarId decl.fvarId
let decl := { decl with binderName, fvarId, type, value }
modifyLCtx fun lctx => lctx.addLetDecl decl
@@ -116,7 +62,7 @@ def internalizeLetDecl (decl : LetDecl) : InternalizeM LetDecl := do
mutual
partial def internalizeFunDecl (decl : FunDecl) : InternalizeM FunDecl := do
let type internalizeExpr decl.type
let type normExpr decl.type
let binderName refreshBinderName decl.binderName
let params decl.params.mapM internalizeParam
let value internalizeCode decl.value
@@ -131,11 +77,11 @@ partial def internalizeCode (code : Code) : InternalizeM Code := do
| .fun decl k => return .fun ( internalizeFunDecl decl) ( internalizeCode k)
| .jp decl k => return .jp ( internalizeFunDecl decl) ( internalizeCode k)
| .return fvarId => withNormFVarResult ( normFVar fvarId) fun fvarId => return .return fvarId
| .jmp fvarId args => withNormFVarResult ( normFVar fvarId) fun fvarId => return .jmp fvarId ( internalizeArgs args)
| .unreach type => return .unreach ( internalizeExpr type)
| .jmp fvarId args => withNormFVarResult ( normFVar fvarId) fun fvarId => return .jmp fvarId ( args.mapM normArg)
| .unreach type => return .unreach ( normExpr type)
| .cases c =>
withNormFVarResult ( normFVar c.discr) fun discr => do
let resultType internalizeExpr c.resultType
let resultType normExpr c.resultType
let internalizeAltCode (k : Code) : InternalizeM Code :=
internalizeCode k
let alts c.alts.mapM fun
@@ -164,7 +110,7 @@ def Decl.internalize (decl : Decl) (s : FVarSubst := {}): CompilerM Decl :=
go decl |>.run' s
where
go (decl : Decl) : InternalizeM Decl := do
let type internalizeExpr decl.type
let type normExpr decl.type
let params decl.params.mapM internalizeParam
let value decl.value.mapCodeM internalizeCode
return { decl with type, params, value }

View File

@@ -75,7 +75,7 @@ where
let some decl getDecl? declName | failure
match decl.value with
| .code code =>
guard (!decl.recursive && decl.getArity == args.size)
guard (decl.getArity == args.size)
let params := decl.instantiateParamsLevelParams us
let code := code.instantiateValueLevelParams decl.levelParams us
let code betaReduce params code args (mustInline := true)

View File

@@ -13,9 +13,8 @@ public section
namespace Lean
builtin_initialize metaExt : TagDeclarationExtension
-- set by `addPreDefinitions`; if we ever make `def` elaboration async, it should be moved to
-- remain on the main environment branch
mkTagDeclarationExtension (asyncMode := .async .mainEnv)
-- set by `addPreDefinitions`
mkTagDeclarationExtension (asyncMode := .async .asyncEnv)
/-- Marks in the environment extension that the given declaration has been declared by the user as `meta`. -/
def addMeta (env : Environment) (declName : Name) : Environment :=

View File

@@ -709,10 +709,8 @@ partial def compileDecls (decls : Array Name) (logErrors := true) : CoreM Unit :
finally
res.commitChecked ( getEnv)
let t BaseIO.mapTask checkAct env.checked
-- Do not display reporting range; most uses of `addDecl` are for registering auxiliary decls
-- users should not worry about and other callers can add a separate task with ranges
-- themselves, see `MutualDef`.
Core.logSnapshotTask { stx? := none, reportingRange := .skip, task := t, cancelTk? := cancelTk }
let endRange? := ( getRef).getTailPos?.map fun pos => pos, pos
Core.logSnapshotTask { stx? := none, reportingRange? := endRange?, task := t, cancelTk? := cancelTk }
where doCompile := do
-- don't compile if kernel errored; should be converted into a task dependency when compilation
-- is made async as well

View File

@@ -203,7 +203,7 @@ private partial def beq' : Json → Json → Bool
| _, _ => false
instance : BEq Json where
beq := private beq'
beq := beq'
private partial def hash' : Json UInt64
| null => 11
@@ -216,7 +216,7 @@ private partial def hash' : Json → UInt64
mixHash 29 <| kvPairs.foldl (init := 7) fun r k v => mixHash r <| mixHash (hash k) (hash' v)
instance : Hashable Json where
hash := private hash'
hash := hash'
def mkObj (o : List (String × Json)) : Json :=
obj <| Std.TreeMap.Raw.ofList o

View File

@@ -199,8 +199,8 @@ private partial def toStringAux {α : Type} : Trie α → List Format
[ format (repr c), (Format.group $ Format.nest 4 $ flip Format.joinSep Format.line $ toStringAux t) ]
) cs.toList ts.toList
instance {α : Type} : ToString (Trie α) where
toString t := private (flip Format.joinSep Format.line $ toStringAux t).pretty
instance {α : Type} : ToString (Trie α) :=
fun t => (flip Format.joinSep Format.line $ toStringAux t).pretty
end Trie

View File

@@ -41,5 +41,5 @@ private partial def cToString : Content → String
| Content.Character c => c
end
instance : ToString Element := private_decl% eToString
instance : ToString Content := private_decl% cToString
instance : ToString Element := eToString
instance : ToString Content := cToString

View File

@@ -227,8 +227,6 @@ def applyDerivingHandlers (className : Name) (typeNames : Array Name) : CommandE
-- When any of the types are private, the deriving handler will need access to the private scope
-- (and should also make sure to put its outputs in the private scope).
withoutExporting (when := typeNames.any isPrivateName) do
-- Deactivate some linting options that only make writing deriving handlers more painful.
withScope (fun sc => { sc with opts := sc.opts.setBool `warn.exposeOnPrivate false }) do
withTraceNode `Elab.Deriving (fun _ => return m!"running deriving handlers for `{.ofConstName className}`") do
match ( derivingHandlersRef.get).find? className with
| some handlers =>

View File

@@ -284,7 +284,7 @@ private def elabHeaders (views : Array DefView) (expandedDeclIds : Array ExpandD
let cancelTk? := ( readThe Core.Context).cancelTk?
let bodySnap := {
stx? := view.value
reportingRange := .ofOptionInheriting <|
reportingRange? :=
if newTacTask?.isSome then
-- Only use first line of body as range when we have incremental tactics as otherwise we
-- would cover their progress
@@ -1140,11 +1140,6 @@ private def checkAllDeclNamesDistinct (preDefs : Array PreDefinition) : TermElab
structure AsyncBodyInfo where
deriving TypeName
register_builtin_option warn.exposeOnPrivate : Bool := {
defValue := true
descr := "warn about uses of `@[expose]` on private declarations"
}
def elabMutualDef (vars : Array Expr) (sc : Command.Scope) (views : Array DefView) : TermElabM Unit :=
if isExample views then
withoutModifyingEnv do
@@ -1244,23 +1239,10 @@ where
processDeriving #[header]
async.commitCheckEnv ( getEnv)
Core.logSnapshotTask { stx? := none, task := ( BaseIO.asTask (act ())), cancelTk? := cancelTk }
-- Also add explicit snapshot task for showing progress of kernel checking; `addDecl` does not
-- do this by default
Core.logSnapshotTask { stx? := none, cancelTk? := none, task := ( getEnv).checked.map fun _ =>
default
}
applyAttributesAt declId.declName view.modifiers.attrs .afterTypeChecking
applyAttributesAt declId.declName view.modifiers.attrs .afterCompilation
finishElab headers (isExporting := false) := withFunLocalDecls headers fun funFVars => do
let env getEnv
if warn.exposeOnPrivate.get ( getOptions) then
if env.header.isModule && !env.isExporting then
for header in headers do
for attr in header.modifiers.attrs do
if attr.name == `expose then
logWarningAt attr.stx m!"Redundant `[expose]` attribute, it is meaningful on public \
definitions only"
withExporting (isExporting :=
headers.any (fun header =>
header.modifiers.isInferredPublic env &&
@@ -1383,7 +1365,8 @@ private def logGoalsAccomplishedSnapshotTask (views : Array DefView)
let logGoalsAccomplishedTask BaseIO.mapTask (t := tree.waitAll) logGoalsAccomplishedAct
Core.logSnapshotTask {
stx? := none
reportingRange := .skip
-- Use first line of the mutual block to avoid covering the progress of the whole mutual block
reportingRange? := ( getRef).getPos?.map fun pos => pos, pos
task := logGoalsAccomplishedTask
cancelTk? := none
}
@@ -1403,9 +1386,7 @@ def elabMutualDef (ds : Array Syntax) : CommandElabM Unit := do
let modifiers elabModifiers d[0]
if ds.size > 1 && modifiers.isNonrec then
throwErrorAt d "invalid use of 'nonrec' modifier in 'mutual' block"
let mut view
withExporting (isExporting := modifiers.visibility.isInferredPublic ( getEnv)) do
mkDefView modifiers d[1]
let mut view mkDefView modifiers d[1]
if view.kind != .example && view.value matches `(declVal| := rfl) then
view := view.markDefEq
let fullHeaderRef := mkNullNode #[d[0], view.headerRef]

View File

@@ -67,6 +67,12 @@ register_builtin_option bootstrap.inductiveCheckResultingUniverse : Bool := {
This option may be deleted in the future after we improve the validator"
}
register_builtin_option debug.inductiveCheckPositivity : Bool := {
defValue := true
descr := "Run elaborator checks for positivity of inductive types. Disabling this can be \
useful for debugging the elaborator or when stress-testing the kernel with invalid inductive types."
}
/-- View of a constructor. Only `ref`, `modifiers`, `declName`, and `declId` are required by the mutual inductive elaborator itself. -/
structure CtorView where
/-- Syntax for the whole constructor. -/
@@ -558,7 +564,7 @@ This is likely a mistake. The correct solution would be `Type (max u 1)` rather
but by this point it is impossible to rectify. So, for `u ≤ ?r + 1` we record the pair of `u` and `1`
so that we can inform the user what they should have probably used instead.
-/
private def accLevel (u : Level) (r : Level) (rOffset : Nat) : ExceptT MessageData (StateT AccLevelState Id) Unit := do
def accLevel (u : Level) (r : Level) (rOffset : Nat) : ExceptT MessageData (StateT AccLevelState Id) Unit := do
go u rOffset
where
go (u : Level) (rOffset : Nat) : ExceptT MessageData (StateT AccLevelState Id) Unit := do
@@ -579,7 +585,7 @@ where
/--
Auxiliary function for `updateResultingUniverse`. Applies `accLevel` to the given constructor parameter.
-/
private def accLevelAtCtor (ctorParam : Expr) (r : Level) (rOffset : Nat) : StateT AccLevelState TermElabM Unit := do
def accLevelAtCtor (ctorParam : Expr) (r : Level) (rOffset : Nat) : StateT AccLevelState TermElabM Unit := do
let type inferType ctorParam
let u instantiateLevelMVars ( getLevel type)
match ( modifyGet fun s => accLevel u r rOffset |>.run |>.run s) with
@@ -779,6 +785,84 @@ where
/- Underconstrained, but not an error. -/
pure ()
structure PositivityExtState where
map : PHashMap (Name × Nat) (Except Exception Unit) := {}
deriving Inhabited
/- Simple local extension for caching/memoization -/
builtin_initialize positivityExt : EnvExtension PositivityExtState
-- Using `local` allows us to use the extension in `realizeConst` without specifying `replay?`.
-- The resulting state can still be accessed on the generated declarations using `findStateAsync`;
-- see below
registerEnvExtension (pure {}) (asyncMode := .local)
private def positivityExt.getOrSet (key : Name × Nat) (act : CoreM Unit) := do
match (positivityExt.getState (asyncMode := .async .asyncEnv) (asyncDecl := key.1) ( getEnv)).map.find? key with
| some r =>
liftExcept r
| none =>
let r observing act
modifyEnv fun env =>
positivityExt.modifyState env (fun s => { s with map := s.map.insert key r })
liftExcept r
/--
Throws an exception unless the `i`th parameter of the inductive type only occurrs in
positive position.
-/
partial def isIndParamPositive (info : InductiveVal) (i : Nat) : CoreM Unit := do
-- Consistently use the info of the first inductive in the group
if info.name != info.all[0]! then
return ( isIndParamPositive ( getConstInfoInduct info.all[0]!) i)
positivityExt.getOrSet (info.name, i) do MetaM.run' do
trace[Elab.inductive] "checking positivity of #{i+1} in {.ofConstName info.name}"
for indName in info.all do
let info getConstInfoInduct indName
for con in info.ctors do
let con getConstInfoCtor con
forallTelescopeReducing con.type fun xs _t => do
-- TODO: Check for occurrences in the indices of t?
let params := xs[0...info.numParams]
let p := params[i]!.fvarId!
for conArg in xs[info.numParams...*] do
forallTelescopeReducing ( inferType conArg) fun conArgArgs conArgRes => do
for conArgArg in conArgArgs do
if ( inferType conArgArg).hasAnyFVar (· == p) then
throwError "Non-positive occurrence of parameter `{mkFVar p}` in type of {.ofConstName con.name}"
let conArgRes whnf conArgRes
if conArgRes.hasAnyFVar (· == p) then
conArgRes.withApp fun fn args => do
if fn == mkFVar p then
for arg in args do
if arg.hasAnyFVar (· == p) then
throwError "Non-positive occurrence of parameter `{mkFVar p}` in type of {.ofConstName con.name}, \
in application of the parameter itself."
else if let some fn := fn.constName? then
if info.all.contains fn then
-- Recursive occurrence of an inductive type of this group.
-- Params must match by construction but check indices
for idxArg in args[info.numParams...*] do
if idxArg.hasAnyFVar (· == p) then
throwError "Non-positive occurrence of parameter `{mkFVar p}` in type of {.ofConstName con.name}, \
in index of {.ofConstName fn}"
else if ( isInductive fn) then
let info' getConstInfoInduct fn
for i in 0...info'.numParams, pe in args[0...info'.numParams] do
if pe.hasAnyFVar (· == p) then
try
isIndParamPositive info' i
catch _ =>
throwError "Non-positive occurrence of parameter `{mkFVar p}` in type of {.ofConstName con.name}, \
in parameter #{i+1} of {.ofConstName fn}"
else
throwError "Non-positive occurrence of parameter `{mkFVar p}` in type of {.ofConstName con.name}, \
cannot nest through {.ofConstName fn}"
else
throwError "Non-positive occurrence of parameter `{mkFVar p}` in type of {.ofConstName con.name}, \
cannot nest through {fn}"
/-- Checks the universe constraints for each constructor. -/
private def checkResultingUniverses (views : Array InductiveView) (elabs' : Array InductiveElabStep2)
(numParams : Nat) (indTypes : List InductiveType) : TermElabM Unit := do
@@ -803,6 +887,84 @@ private def checkResultingUniverses (views : Array InductiveView) (elabs' : Arra
which is not less than or equal to the inductive type's resulting universe level{indentD u}"
withCtorRef views ctor.name <| throwError msg
private partial def checkPositivity (views : Array InductiveView) (indFVars : Array Expr) (numParams : Nat) (indTypes : List InductiveType) : TermElabM Unit := do
unless debug.inductiveCheckPositivity.get ( getOptions) do return
for h : i in *...indTypes.length do
let view := views[i]!
let indType := indTypes[i]
for ctor in indType.ctors do
withCtorRef views ctor.name do
forallTelescopeReducing ctor.type fun xs retTy => do
let params := xs[*...numParams]
for x in xs, i in *...xs.size do
prependError m!"In argument #{i+1} of constructor {ctor.name}:" do
go params ( inferType x)
isValidIndApp retTy
where
hasIndOcc (t : Expr) : Option Expr :=
indFVars.find? (fun indFVar => t.hasAnyFVar (· == indFVar.fvarId!))
-- cf. is_valid_ind_app in inductive.cpp
isValidIndApp (e : Expr) : TermElabM Unit := do
e.withApp fun fn args => do
if let some i := indFVars.findIdx? (fun indFVar => fn == indFVar) then
-- The parameters are already checked in `checkParamOccs`
for arg in args[numParams...*] do
if let some indFVar := hasIndOcc arg then
throwError "Invalid occurrence of inductive type `{indFVar}`: The indices in the \
occurrence may not mention the inductive type itself."
else
throwError "Non-positive occurrence of the inductive type in constructor argument:{inlineExpr e}"
-- cf. check_positivity in inductive.cpp
go (params : Array Expr) (t : Expr) : TermElabM Unit := do
let t instantiateMVars ( whnf t)
if let some indFVar := hasIndOcc t then
-- Argument has recursive occurrences
forallTelescopeReducing t fun xs t => do
for x in xs do
if let some indFVar := hasIndOcc ( inferType x) then
throwError "Non-positive occurrence of inductive type `{indFVar}`"
let t whnf t
t.withApp fun fn args => do
if let some fn := fn.constName? then
-- Check for valid nested induction
unless ( isInductive fn) do
throwError "Non-positive occurrence of inductive type `{indFVar}`: \
Nested occurrences can only occur in inductive types, not in `{.ofConstName fn}`."
let info getConstInfoInduct fn
unless args.size = info.numParams + info.numIndices do
throwError "Non-positive occurrence of inductive type `{indFVar}`: \
Invalid occurrence of {indFVar} in unsaturated call of {.ofConstName fn}."
for i in 0...info.numParams, pe in args[0...info.numParams] do
if let some indFVar := hasIndOcc pe then
try isIndParamPositive info i
catch e =>
let msg := m!"Invalid occurrence of inductive type `{indFVar}`, parameter #{i+1} of \
`{.ofConstName fn}` is not positive."
let msg := msg ++ .note m!"That parameter is not positive:{indentD e.toMessageData}"
throwError msg
-- Here, we allow lambdas in parameters. The kernel actually substitutes these while
-- doing the transformation for nested inductives, and may reduce these lambdas away.
-- We approximate this behavior for now. See `lean/run/nestedInductiveUniverse.lean`
-- for an example
lambdaTelescope pe fun _xs pe => do
-- We do not consider the domains of the lambda-bound variables
-- as negative occurrences, as they will be reduced away.
go params pe
-- The kernel admits no local variables in the parameters (#1964)
-- so check for any fvar that isn't one of the indFVars or params
if let some e := pe.find? (fun e => e.isFVar && !indFVars.contains e && !params.contains e) then
throwError "Nested inductive datatype parameters cannot contain local variable `{e}`."
for ie in args[info.numParams...args.size] do
if let some indFVar := hasIndOcc ie then
throwError "Invalid occurrence of inductive type `{indFVar}`, must not occur in \
index of `{.ofConstName fn}`"
else
isValidIndApp t
private def collectUsed (indTypes : List InductiveType) : StateRefT CollectFVars.State MetaM Unit := do
indTypes.forM fun indType => do
indType.type.collectFVars
@@ -911,6 +1073,8 @@ private def mkInductiveDecl (vars : Array Expr) (elabs : Array InductiveElabStep
propagateUniversesToConstructors numParams indTypes
levelMVarToParam indTypes none
checkResultingUniverses views elabs' numParams indTypes
unless isUnsafe do
checkPositivity views indFVars numParams indTypes
elabs'.forM fun elab' => elab'.finalizeTermElab
let usedLevelNames := collectLevelParamsInInductive indTypes
match sortDeclLevelParams scopeLevelNames allUserLevelNames usedLevelNames with

View File

@@ -502,7 +502,7 @@ private instance : ToMessageData ExpandedFieldVal where
private instance : ToMessageData ExpandedField where
toMessageData field := m!"field '{field.name}' is {field.val}"
private abbrev ExpandedFields := NameMap ExpandedField
abbrev ExpandedFields := NameMap ExpandedField
/--
Normalizes and expands the field views.

View File

@@ -17,12 +17,12 @@ public section
namespace Lean.Elab.Tactic
open Meta Parser.Tactic Command
structure ConfigItemView where
private structure ConfigItemView where
ref : Syntax
option : Ident
value : Term
/-- Whether this was using `+`/`-`, to be able to give a better error message on type mismatch. -/
bool : Bool := false
(bool : Bool := false)
/-- Interprets the `config` as an array of option/value pairs. -/
def mkConfigItemViews (c : TSyntaxArray ``configItem) : Array ConfigItemView :=

View File

@@ -147,7 +147,8 @@ partial def computeMVarBetaPotentialForSPred (xs : Array Expr) (σs : Expr) (e :
let s mkFreshExprMVar σ
e := e.beta #[s]
let (r, _) simp e ctx
-- In practice we only need to reduce `fun s => ...` and `SPred.pure`.
-- In practice we only need to reduce `fun s => ...`, `SVal.curry` and functions that operate
-- on the state tuple bound by `SVal.curry`.
-- We could write a custom function should `simp` become a bottleneck.
e := r.expr
let count countBVarDependentMVars xs e

View File

@@ -18,11 +18,8 @@ open Lean Expr Meta PrettyPrinter Delaborator SubExpr
@[builtin_delab app.Std.Tactic.Do.MGoalEntails]
private partial def delabMGoal : Delab := do
-- Std.Tactic.Do.MGoalEntails.{u} : ∀ {σs : List (Type u)}, SPred σs → SPred σs → Prop
-- only accept when there are at least 3 arguments.
let e getExpr
guard <| e.getAppNumArgs >= 3
let (_, _, hyps) withAppFn <| withAppArg <| delabHypotheses ({}, {}, #[])
-- delaborate
let (_, _, hyps) withAppFn withAppArg <| delabHypotheses ({}, {}, #[])
let target SPred.Notation.unpack ( withAppArg <| delab)
-- build syntax
@@ -60,10 +57,8 @@ where
accessibles := accessibles.insert name idx
return (accessibles, inaccessibles, lines.push stx)
if (parseAnd? hyps).isSome then
-- SPred.and : ∀ {σs : List Type}, SPred σs → SPred σs → SPred σs
-- first delab `rhs` in `SPred.and σs lhs rhs`, then `lhs`.
let acc_rhs withAppArg <| delabHypotheses acc
let acc_lhs withAppFn <| withAppArg <| delabHypotheses acc_rhs
let acc_lhs withAppFn withAppArg <| delabHypotheses acc_rhs
return acc_lhs
else
failure

View File

@@ -20,7 +20,7 @@ open Lean Elab Tactic Meta
-- set_option pp.all true in
-- #check ⌜False⌝
private def falseProp (u : Level) (σs : Expr) : Expr := -- ⌜False⌝ standing in for an empty conjunction of hypotheses
SPred.mkPure u σs (mkConst ``False)
mkApp3 (mkConst ``SVal.curry [u]) (mkApp (mkConst ``ULift [u, 0]) (.sort .zero)) σs <| mkLambda `tuple .default (mkApp (mkConst ``SVal.StateTuple [u]) σs) (mkApp2 (mkConst ``ULift.up [u, 0]) (.sort .zero) (mkConst ``False))
@[builtin_tactic Lean.Parser.Tactic.mexfalso]
def elabMExfalso : Tactic | _ => do

View File

@@ -41,10 +41,13 @@ def SPred.mkType (u : Level) (σs : Expr) : Expr :=
-- set_option pp.all true in
-- #check ⌜True⌝
def SPred.mkPure (u : Level) (σs : Expr) (p : Expr) : Expr :=
mkApp2 (mkConst ``SPred.pure [u]) σs p
mkApp3 (mkConst ``SVal.curry [u]) (mkApp (mkConst ``ULift [u, 0]) (.sort .zero)) σs <|
mkLambda `tuple .default (mkApp (mkConst ``SVal.StateTuple [u]) σs) <|
mkApp2 (mkConst ``ULift.up [u, 0]) (.sort .zero) (Expr.liftLooseBVars p 0 1)
def SPred.isPure? : Expr Option (Level × Expr × Expr)
| mkApp2 (.const ``SPred.pure [u]) σs p => some (u, σs, p)
| mkApp3 (.const ``SVal.curry [u]) (mkApp (.const ``ULift _) (.sort .zero)) σs <|
.lam _ _ (mkApp2 (.const ``ULift.up _) _ p) _ => some (u, σs, (Expr.lowerLooseBVars p 0 1))
| _ => none
def emptyHypName := `emptyHyp
@@ -88,16 +91,10 @@ def SPred.mkAnd (u : Level) (σs lhs rhs : Expr) : Expr × Expr :=
def TypeList.mkType (u : Level) : Expr := mkApp (mkConst ``List [.succ u]) (mkSort (.succ u))
def TypeList.mkNil (u : Level) : Expr := mkApp (mkConst ``List.nil [.succ u]) (mkSort (.succ u))
def TypeList.mkCons (u : Level) (hd tl : Expr) : Expr := mkApp3 (mkConst ``List.cons [.succ u]) (mkSort (.succ u)) hd tl
def TypeList.length (σs : Expr) : MetaM Nat := do
let mut σs whnfR σs
let mut n := 0
while σs.isAppOfArity ``List.cons 3 do
n := n+1
σs whnfR (σs.getArg! 2)
return n
def parseAnd? (e : Expr) : Option (Level × Expr × Expr × Expr) :=
(e.getAppFn.constLevels![0]!, ·) <$> e.app3? ``SPred.and
(e.getAppFn.constLevels![0]!, ·) <$> e.app3? ``SPred.and
<|> (0, TypeList.mkNil 0, ·) <$> e.app2? ``And
structure MGoal where
u : Level
@@ -142,20 +139,13 @@ partial def MGoal.findHyp? (goal : MGoal) (name : Name) : Option (SubExpr.Pos ×
else
panic! "MGoal.findHyp?: hypothesis without proper metadata: {e}"
def checkHasType (expr : Expr) (expectedType : Expr) (suppressWarning : Bool := false) : MetaM Unit := do
check expr
check expectedType
let exprType inferType expr
unless isDefEqGuarded exprType expectedType do
throwError "checkHasType: the expression's inferred type and its expected type did not match.\n
expr: {indentExpr expr}\n
has inferred type: {indentExpr exprType}\n
but the expected type was: {indentExpr expectedType}"
unless suppressWarning do
logWarning m!"stray checkHasType {expr} : {expectedType}"
def MGoal.checkProof (goal : MGoal) (prf : Expr) (suppressWarning : Bool := false) : MetaM Unit := do
checkHasType prf goal.toExpr suppressWarning
check prf
let prf_type inferType prf
unless isDefEq goal.toExpr prf_type do
throwError "MGoal.checkProof: the proof and its supposed type did not match.\ngoal: {goal.toExpr}\nproof: {prf_type}"
unless suppressWarning do
logWarning m!"stray MGoal.checkProof {prf_type} {goal.toExpr}"
def getFreshHypName : TSyntax ``binderIdent CoreM (Name × Syntax)
| `(binderIdent| $name:ident) => pure (name.getId, name)

View File

@@ -53,8 +53,10 @@ def elabMPure : Tactic
replaceMainGoal [m.mvarId!]
| _ => throwUnsupportedSyntax
macro "mpure_intro" : tactic => `(tactic| apply Pure.intro)
def MGoal.triviallyPure (goal : MGoal) : OptionT MetaM Expr := do
let mv mkFreshExprMVar goal.toExpr
let ([], _) try runTactic mv.mvarId! ( `(tactic| apply $(mkIdent ``Std.Do.SPred.Tactic.Pure.intro); trivial)) catch _ => failure
let ([], _) try runTactic mv.mvarId! ( `(tactic| apply Pure.intro; trivial)) catch _ => failure
| failure
return mv
return mv.consumeMData

View File

@@ -48,23 +48,16 @@ partial def mRefineCore (goal : MGoal) (pat : MRefinePat) (k : MGoal → TSyntax
| .tuple [p] => mRefineCore goal p k
| .tuple (p::ps) => do
let T whnfR goal.target
let f := T.getAppFn'
let args := T.getAppArgs
trace[Meta.debug] "f: {f}, args: {args}"
if f.isConstOf ``SPred.and && args.size >= 3 then
let T₁ := args[1]!.beta args[3...*]
let T₂ := args[2]!.beta args[3...*]
if let some (u, σs, T₁, T₂) := parseAnd? T.consumeMData then
let prf₁ mRefineCore { goal with target := T₁ } p k
let prf₂ mRefineCore { goal with target := T₂ } (.tuple ps) k
return mkApp6 (mkConst ``SPred.and_intro [goal.u]) goal.σs goal.hyps T₁ T₂ prf₁ prf₂
else if f.isConstOf ``SPred.exists && args.size >= 3 then
let α := args[0]!
let ψ := args[2]!
return mkApp6 (mkConst ``SPred.and_intro [u]) σs goal.hyps T₁ T₂ prf₁ prf₂
else if let some (α, σs, ψ) := T.app3? ``SPred.exists then
let some witness patAsTerm p (some α) | throwError "pattern does not elaborate to a term to instantiate ψ"
let prf mRefineCore { goal with target := ψ.beta (#[witness] ++ args[3...*]) } (.tuple ps) k
let prf mRefineCore { goal with target := ψ.betaRev #[witness] } (.tuple ps) k
let u getLevel α
return mkApp6 (mkConst ``SPred.exists_intro' [u, goal.u]) α goal.σs goal.hyps ψ witness prf
else throwError "Neither a conjunction nor an existential quantifier {T}"
return mkApp6 (mkConst ``SPred.exists_intro' [u, goal.u]) α σs goal.hyps ψ witness prf
else throwError "Neither a conjunction nor an existential quantifier {goal.target}"
@[builtin_tactic Lean.Parser.Tactic.mrefine]
def elabMRefine : Tactic

View File

@@ -124,7 +124,7 @@ def dischargeMGoal (goal : MGoal) (goalTag : Name) : n Expr := do
liftMetaM <| do trace[Elab.Tactic.Do.spec] "dischargeMGoal: {goal.target}"
-- 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 `SPred.pure (σs:=[Nat]) (s = 4) s` and `SPred.pure` is
-- (Recall that `⌜s = 4⌝ s` is `SVal.curry (σs:=[Nat]) (fun _ => s = 4) s` and `SVal.curry` is
-- semi-reducible.)
-- We also try `mpure_intro; trivial` through `goal.triviallyPure` here because later on an
-- assignment like `⌜s = ?c⌝` becomes impossible to discharge because `?c` will get abstracted
@@ -136,10 +136,17 @@ def dischargeMGoal (goal : MGoal) (goalTag : Name) : n Expr := do
liftMetaM <| do trace[Elab.Tactic.Do.spec] "proof: {prf}"
return prf
def mkPreTag (goalTag : Name) : Name := Id.run do
let dflt := goalTag ++ `pre1
let .str p s := goalTag | return dflt
unless "pre".isPrefixOf s do return dflt
let some n := (s.toSubstring.drop 3).toString.toNat? | return dflt
return .str p ("pre" ++ toString (n + 1))
/--
Returns the proof and the list of new unassigned MVars.
-/
def mSpec (goal : MGoal) (elabSpecAtWP : Expr n SpecTheorem) (goalTag : Name) : n Expr := do
def mSpec (goal : MGoal) (elabSpecAtWP : Expr n SpecTheorem) (goalTag : Name) (mkPreTag := mkPreTag) : n Expr := do
-- First instantiate `fun s => ...` in the target via repeated `mintro ∀s`.
mIntroForallN goal goal.target.consumeMData.getNumHeadLambdas fun goal => do
-- Elaborate the spec for the wp⟦e⟧ app in the target
@@ -149,8 +156,11 @@ def mSpec (goal : MGoal) (elabSpecAtWP : Expr → n SpecTheorem) (goalTag : Name
let wp := T.getArg! 2
let specThm elabSpecAtWP wp
-- The precondition of `specThm` might look like `⌜?n = nₛ ∧ ?m = b⌝`, which expands to
-- `SPred.pure (?n = n ∧ ?m = b)`.
-- The precondition of `specThm` might look like `⌜?n = Natₛ ∧ ?m = Bool⌝`, which expands to
-- `SVal.curry (fun tuple => ?n = SVal.uncurry (getThe Nat tuple) ∧ ?m = SVal.uncurry (getThe Bool tuple))`.
-- Note that the assignments for `?n` and `?m` depend on the bound variable `tuple`.
-- Here, we further eta expand and simplify according to `etaPotential` so that the solutions for
-- `?n` and `?m` do not depend on `tuple`.
let residualEta := specThm.etaPotential - (T.getAppNumArgs - 4) -- 4 arguments expected for PredTrans.apply
mIntroForallN goal residualEta fun goal => do
@@ -191,7 +201,7 @@ def mSpec (goal : MGoal) (elabSpecAtWP : Expr → n SpecTheorem) (goalTag : Name
if !HPRfl then
-- let P := (← reduceProjBeta? P).getD P
-- Try to avoid creating a longer name if the postcondition does not need to create a goal
let tag := if !QQ'Rfl then goalTag ++ `pre else goalTag
let tag := if !QQ'Rfl then mkPreTag goalTag else goalTag
let HPPrf dischargeMGoal { goal with target := P } tag
prePrf := mkApp6 (mkConst ``SPred.entails.trans [u]) goal.σs goal.hyps P goal.target HPPrf

View File

@@ -6,23 +6,21 @@ Authors: Sebastian Graf
module
prelude
import Std.Do.WP
import Std.Do.Triple
import Lean.Elab.Tactic.Do.VCGen.Split
import Lean.Elab.Tactic.Simp
import Lean.Elab.Tactic.Do.ProofMode.Basic
import Lean.Elab.Tactic.Do.ProofMode.Intro
import Lean.Elab.Tactic.Do.ProofMode.Revert
import Lean.Elab.Tactic.Do.ProofMode.Cases
import Lean.Elab.Tactic.Do.ProofMode.Specialize
import Lean.Elab.Tactic.Do.ProofMode.Pure
import Lean.Elab.Tactic.Do.LetElim
import Lean.Elab.Tactic.Do.Spec
import Lean.Elab.Tactic.Do.Attr
import Lean.Elab.Tactic.Do.Syntax
import Lean.Elab.Tactic.Induction
public import Std.Do.WP
public import Std.Do.Triple
public import Lean.Elab.Tactic.Simp
public import Lean.Elab.Tactic.Do.ProofMode.Basic
public import Lean.Elab.Tactic.Do.ProofMode.Intro
public import Lean.Elab.Tactic.Do.ProofMode.Revert
public import Lean.Elab.Tactic.Do.ProofMode.Cases
public import Lean.Elab.Tactic.Do.ProofMode.Specialize
public import Lean.Elab.Tactic.Do.ProofMode.Pure
public import Lean.Elab.Tactic.Do.LetElim
public import Lean.Elab.Tactic.Do.Spec
public import Lean.Elab.Tactic.Do.Attr
public import Lean.Elab.Tactic.Do.Syntax
public import Lean.Elab.Tactic.Do.VCGen.Basic
public import Lean.Elab.Tactic.Do.VCGen.Split
public section
@@ -42,22 +40,12 @@ private def ProofMode.MGoal.withNewProg (goal : MGoal) (e : Expr) : MGoal :=
namespace VCGen
structure Result where
invariants : Array MVarId
vcs : Array MVarId
partial def genVCs (goal : MVarId) (ctx : Context) (fuel : Fuel) : MetaM Result := do
partial def genVCs (goal : MVarId) (ctx : Context) (fuel : Fuel) : MetaM (Array MVarId) := do
let (mvar, goal) mStartMVar goal
mvar.withContext <| withReducible do
let (prf, state) StateRefT'.run (ReaderT.run (onGoal goal ( mvar.getTag)) ctx) { fuel }
mvar.assign prf
for h : idx in [:state.invariants.size] do
let mv := state.invariants[idx]
mv.setTag (Name.mkSimple ("inv" ++ toString (idx + 1)))
for h : idx in [:state.vcs.size] do
let mv := state.vcs[idx]
mv.setTag (Name.mkSimple ("vc" ++ toString (idx + 1)) ++ ( mv.getTag))
return { invariants := state.invariants, vcs := state.vcs }
return state.vcs
where
onFail (goal : MGoal) (name : Name) : VCGenM Expr := do
-- trace[Elab.Tactic.Do.vcgen] "fail {goal.toExpr}"
@@ -159,11 +147,7 @@ where
let (prf, specHoles) try
let specThm findSpec ctx.specThms wp
trace[Elab.Tactic.Do.vcgen] "Candidate spec for {f.constName!}: {specThm.proof}"
-- We eta-expand as far here as goal.σs permits.
-- This is so that `mSpec` can frame hypotheses involving uninstantiated loop invariants.
-- It is absolutely crucial that we do not lose these hypotheses in the inductive step.
collectFreshMVars <| mIntroForallN goal ( TypeList.length goal.σs) fun goal =>
withDefault <| mSpec goal (fun _wp => return specThm) name
withDefault <| collectFreshMVars <| mSpec goal (fun _wp => return specThm) name
catch ex =>
trace[Elab.Tactic.Do.vcgen] "Failed to find spec for {wp}. Trying simp. Reason: {ex.toMessageData}"
-- Last resort: Simp and try again
@@ -267,7 +251,6 @@ where
-- the stateful hypothesis of the goal.
let mkJoinGoal (e : Expr) :=
let wp := mkApp5 c m ps instWP α e
let σs := mkApp (mkConst ``PostShape.args [uWP]) ps
let args := args.set! 2 wp |>.take 4
let target := mkAppN (mkConst ``PredTrans.apply [uWP]) args
{ u := uWP, σs, hyps := emptyHyp uWP σs, target : MGoal }
@@ -275,8 +258,8 @@ where
let joinPrf mkLambdaFVars (joinParams.push h) ( onWPApp (mkJoinGoal (mkAppN fv joinParams)) name)
let joinGoal mkForallFVars (joinParams.push h) (mkJoinGoal (zetadVal.beta joinParams)).toExpr
-- `joinPrf : joinGoal` by zeta
-- checkHasType joinPrf joinGoal
return (joinPrf, joinGoal)
withLetDecl ( mkFreshUserName `joinPrf) joinGoal joinPrf (kind := .implDetail) fun joinPrf => do
let prf onSplit goal info name fun idx params doGoal => do
let altLCtxIdx := ( getLCtx).numIndices
@@ -317,23 +300,21 @@ where
let φ := mkAndN eqs.toList
let prf mkAndIntroN ( liftMetaM <| joinArgs.mapM mkEqRefl).toList
let φ := φ.abstract newLocals
-- Invariant: `prf : (let newLocals; φ)[joinParamsjoinArgs]`, and `joinParams` does not occur in `prf`
-- Invariant: `prf : (fun joinParams => φ) joinArgs`
let (_, φ, prf) newLocalDecls.foldrM (init := (newLocals, φ, prf)) fun decl (locals, φ, prf) => do
let locals := locals.pop
match decl.value? with
| some v =>
let type := ( instantiateMVars decl.type).abstract locals
let val := ( instantiateMVars v).abstract locals
let type := decl.type.abstract locals
let val := v.abstract locals
let φ := mkLet decl.userName type val φ (nondep := decl.isNondep)
return (locals, φ, prf)
| none =>
let type := ( instantiateMVars decl.type).abstract locals
trace[Elab.Tactic.Do.vcgen] "{decl.type} abstracted over {locals}: {type}"
let u getLevel decl.type
let type := decl.type.abstract locals
let u getLevel type
let ψ := mkLambda decl.userName decl.binderInfo type φ
let ψPrf := mkLambda decl.userName decl.binderInfo decl.type φ
let φ := mkApp2 (mkConst ``Exists [u]) type ψ
let prf := mkApp4 (mkConst ``Exists.intro [u]) decl.type ψPrf decl.toExpr prf
let prf := mkApp4 (mkConst ``Exists.intro [u]) type ψ decl.toExpr prf
return (locals, φ, prf)
-- Abstract φ over the altParams in order to instantiate info.hyps below
@@ -346,10 +327,8 @@ where
info.hyps.assign φ
let φ := φ.beta (joinArgs ++ altParams)
let prf := prf.beta joinArgs
-- checkHasType prf φ
let jumpPrf := mkAppN info.joinPrf joinArgs
let jumpGoal inferType jumpPrf
-- checkHasType jumpPrf jumpGoal
let .forallE _ φ' .. := jumpGoal | throwError "jumpGoal {jumpGoal} is not a forall"
trace[Elab.Tactic.Do.vcgen] "φ applied: {φ}, prf applied: {prf}, type: {← inferType prf}"
let rwPrf rwIfOrMatcher info.altIdx φ'
@@ -362,62 +341,6 @@ where
end VCGen
def elabInvariants (stx : Syntax) (invariants : Array MVarId) : TacticM Unit := do
let some stx := stx.getOptional? | return ()
let stx : TSyntax ``invariantAlts := stx
match stx with
| `(invariantAlts| using invariants $alts*) =>
for alt in alts do
match alt with
| `(invariantAlt| | $ns,* => $rhs) =>
for ref in ns.getElems do
let n := ref.getNat
if n = 0 then
logErrorAt ref "Invariant index 0 is invalid. Invariant indices start at 1 just as the case labels `inv<n>`."
continue
let some mv := invariants[n-1]? | do
logErrorAt ref m!"Invariant index {n} is out of bounds. Invariant indices start at 1 just as the case labels `inv<n>`. There were {invariants.size} invariants."
continue
if mv.isAssigned then
logErrorAt ref m!"Invariant {n} is already assigned"
continue
discard <| evalTacticAt ( `(tactic| exact $rhs)) mv
| _ => logErrorAt alt "Expected invariantAlt, got {alt}"
| _ => logErrorAt stx "Expected invariantAlts, got {stx}"
private def patchVCAltIntoCaseTactic (alt : TSyntax ``vcAlt) : TSyntax ``case :=
-- syntax vcAlt := sepBy1(caseArg, " | ") " => " tacticSeq
-- syntax case := "case " sepBy1(caseArg, " | ") " => " tacticSeq
alt.raw |>.setKind ``case |>.setArg 0 (mkAtom "case")
partial def elabVCs (stx : Syntax) (vcs : Array MVarId) : TacticM (List MVarId) := do
let some stx := stx.getOptional? | return vcs.toList
match (stx : TSyntax ``vcAlts) with
| `(vcAlts| with $(tactic)? $alts*) =>
let vcs applyPreTac vcs tactic
evalAlts vcs alts
| _ =>
logErrorAt stx "Expected inductionAlts, got {stx}"
return vcs.toList
where
applyPreTac (vcs : Array MVarId) (tactic : Option Syntax) : TacticM (Array MVarId) := do
let some tactic := tactic | return vcs
let mut newVCs := #[]
for vc in vcs do
let vcs try evalTacticAt tactic vc catch _ => pure [vc]
newVCs := newVCs ++ vcs
return newVCs
evalAlts (vcs : Array MVarId) (alts : TSyntaxArray ``vcAlt) : TacticM (List MVarId) := do
let oldGoals getGoals
try
setGoals vcs.toList
for alt in alts do withRef alt <| evalTactic <| patchVCAltIntoCaseTactic alt
pruneSolvedGoals
getGoals
finally
setGoals oldGoals
@[builtin_tactic Lean.Parser.Tactic.mvcgen]
def elabMVCGen : Tactic := fun stx => withMainContext do
if mvcgen.warning.get ( getOptions) then
@@ -428,13 +351,10 @@ def elabMVCGen : Tactic := fun stx => withMainContext do
| none => .unlimited
let goal getMainGoal
let goal if ctx.config.elimLets then elimLets goal else pure goal
let { invariants, vcs } VCGen.genVCs goal ctx fuel
let vcs VCGen.genVCs goal ctx fuel
let runOnVCs (tac : TSyntax `tactic) (vcs : Array MVarId) : TermElabM (Array MVarId) :=
vcs.flatMapM fun vc => List.toArray <$> Term.withSynthesize do
Tactic.run vc (Tactic.evalTactic tac *> Tactic.pruneSolvedGoals)
let invariants Term.TermElabM.run' do
let invariants if ctx.config.leave then runOnVCs ( `(tactic| try mleave)) invariants else pure invariants
elabInvariants stx[3] invariants
let vcs Term.TermElabM.run' do
let vcs if ctx.config.trivial then runOnVCs ( `(tactic| try mvcgen_trivial)) vcs else pure vcs
let vcs if ctx.config.leave then runOnVCs ( `(tactic| try mleave)) vcs else pure vcs
@@ -442,5 +362,4 @@ def elabMVCGen : Tactic := fun stx => withMainContext do
-- Eliminating lets here causes some metavariables in `mkFreshPair_triple` to become nonassignable
-- so we don't do it. Presumably some weird delayed assignment thing is going on.
-- let vcs ← if ctx.config.elimLets then liftMetaM <| vcs.mapM elimLets else pure vcs
let vcs elabVCs stx[4] vcs
replaceMainGoal (invariants ++ vcs).toList
replaceMainGoal vcs.toList

View File

@@ -68,11 +68,8 @@ structure State where
fuel : Fuel := .unlimited
simpState : Simp.State := {}
/--
Holes of type `Invariant` that have been generated so far.
-/
invariants : Array MVarId := #[]
/--
The verification conditions that have been generated so far.
Includes `Type`-valued goals arising from instantiation of specifications.
-/
vcs : Array MVarId := #[]
@@ -91,19 +88,15 @@ def ifOutOfFuel (x : VCGenM α) (k : VCGenM α) : VCGenM α := do
| Fuel.limited 0 => x
| _ => k
def addSubGoalAsVC (goal : MVarId) : VCGenM PUnit := do
let ty goal.getType
if ty.isAppOf ``Std.Do.Invariant then
modify fun s => { s with invariants := s.invariants.push goal }
else
modify fun s => { s with vcs := s.vcs.push goal }
def emitVC (subGoal : Expr) (name : Name) : VCGenM Expr := do
withFreshUserNamesSinceIdx ( read).initialCtxSize do
let m liftM <| mkFreshExprSyntheticOpaqueMVar subGoal (tag := name)
addSubGoalAsVC m.mvarId!
modify fun s => { s with vcs := s.vcs.push m.mvarId! }
return m
def addSubGoalAsVC (goal : MVarId) : VCGenM PUnit := do
modify fun s => { s with vcs := s.vcs.push goal }
def liftSimpM (x : SimpM α) : VCGenM α := do
let ctx read
let s get

View File

@@ -41,8 +41,8 @@ A list of pairs `(numParams, alt)` per match alternative, where `numParams` is t
number of parameters of the alternative and `alt` is the alternative.
-/
def altInfos (info : SplitInfo) : Array (Nat × Expr) := match info with
| ite e => #[(0, e.getArg! 3), (0, e.getArg! 4)]
| dite e => #[(1, e.getArg! 3), (1, e.getArg! 4)]
| ite e => #[(0, e.getArg! 3), (1, e.getArg! 4)]
| dite e => #[(0, e.getArg! 3), (1, e.getArg! 4)]
| matcher matcherApp => matcherApp.altNumParams.mapIdx fun idx numParams =>
(numParams, matcherApp.alts[idx]!)
@@ -98,7 +98,7 @@ def rwIfOrMatcher (idx : Nat) (e : Expr) : MetaM Simp.Result := do
let c := e.getArg! 1
let c := if idx = 0 then c else mkNot c
let .some fv findLocalDeclWithType? c
| throwError "Failed to find proof for if condition {c}"
| throwError "Failed to proof for if condition {c}"
FunInd.rwIfWith (mkFVar fv) e
else
FunInd.rwMatcher idx e

View File

@@ -68,17 +68,6 @@ def elabInitGrindNorm : CommandElab := fun stx =>
Grind.registerNormTheorems pre post
| _ => throwUnsupportedSyntax
private def warnRedundantEMatchArg (s : Grind.EMatchTheorems) (declName : Name) : MetaM Unit := do
let kinds match s.getKindsFor (.decl declName) with
| [] => return ()
| [k] => pure m!"@{k.toAttribute}"
| [.eqLhs gen, .eqRhs _]
| [.eqRhs gen, .eqLhs _] => pure m!"@{(Grind.EMatchTheoremKind.eqBoth gen).toAttribute}"
| ks =>
let ks := ks.map fun k => m!"@{k.toAttribute}"
pure m!"{ks}"
logWarning m!"this parameter is redundant, environment already contains `{declName}` annotated with `{kinds}`"
def elabGrindParams (params : Grind.Params) (ps : TSyntaxArray ``Parser.Tactic.grindParam) (only : Bool) : MetaM Grind.Params := do
let mut params := params
for p in ps do
@@ -136,19 +125,14 @@ where
let info getAsyncConstInfo declName
match info.kind with
| .thm | .axiom | .ctor =>
if params.ematch.containsWithSameKind (.decl declName) kind then
logWarning m!"this parameter is redundant, environment already contains `@{kind.toAttribute} {declName}`"
match kind with
| .eqBoth gen =>
let thm₁ Grind.mkEMatchTheoremForDecl declName (.eqLhs gen) params.symPrios
let thm₂ Grind.mkEMatchTheoremForDecl declName (.eqRhs gen) params.symPrios
if params.ematch.containsWithSamePatterns thm₁.origin thm₁.patterns &&
params.ematch.containsWithSamePatterns thm₂.origin thm₂.patterns then
warnRedundantEMatchArg params.ematch declName
return { params with extra := params.extra.push thm₁ |>.push thm₂ }
let params := { params with extra := params.extra.push ( Grind.mkEMatchTheoremForDecl declName (.eqLhs gen) params.symPrios) }
return { params with extra := params.extra.push ( Grind.mkEMatchTheoremForDecl declName (.eqRhs gen) params.symPrios) }
| _ =>
let thm Grind.mkEMatchTheoremForDecl declName kind params.symPrios
if params.ematch.containsWithSamePatterns thm.origin thm.patterns then
warnRedundantEMatchArg params.ematch declName
return { params with extra := params.extra.push thm }
return { params with extra := params.extra.push ( Grind.mkEMatchTheoremForDecl declName kind params.symPrios) }
| .defn =>
if ( isReducible declName) then
throwError "`{declName}` is a reducible definition, `grind` automatically unfolds them"
@@ -219,7 +203,7 @@ def evalGrindCore
let only := only.isSome
let params := if let some params := params then params.getElems else #[]
if Grind.grind.warning.get ( getOptions) then
logWarningAt ref "The `grind` tactic is new and its behavior may change in the future. This project has used `set_option grind.warning true` to discourage its use."
logWarningAt ref "The `grind` tactic is new and its behaviour may change in the future. This project has used `set_option grind.warning true` to discourage its use."
withMainContext do
let result grind ( getMainGoal) config only params fallback
replaceMainGoal []

View File

@@ -363,7 +363,7 @@ where
stx := mkNullNode altStxs
diagnostics := .empty
inner? := none
finished := { stx? := mkNullNode altStxs, reportingRange := .inherit, task := finished.resultD default, cancelTk? }
finished := { stx? := mkNullNode altStxs, reportingRange? := none, task := finished.resultD default, cancelTk? }
next := Array.zipWith
(fun stx prom => { stx? := some stx, task := prom.resultD default, cancelTk? })
altStxs altPromises

View File

@@ -86,7 +86,7 @@ def mkCoordinateEvalAtomsEq (e : Expr) (n : Nat) : OmegaM Expr := do
mkEqTrans eq ( mkEqSymm (mkApp2 (.const ``LinearCombo.coordinate_eval []) n atoms))
/-- Construct the linear combination (and its associated proof and new facts) for an atom. -/
def mkAtomLinearCombo (e : Expr) : OmegaM (LinearCombo × OmegaM Expr × List Expr) := do
def mkAtomLinearCombo (e : Expr) : OmegaM (LinearCombo × OmegaM Expr × Std.HashSet Expr) := do
let (n, facts) lookup e
return LinearCombo.coordinate n, mkCoordinateEvalAtomsEq e n, facts.getD
@@ -100,7 +100,7 @@ Gives a small (10%) speedup in testing.
I tried using a pointer based cache,
but there was never enough subexpression sharing to make it effective.
-/
partial def asLinearCombo (e : Expr) : OmegaM (LinearCombo × OmegaM Expr × List Expr) := do
partial def asLinearCombo (e : Expr) : OmegaM (LinearCombo × OmegaM Expr × Std.HashSet Expr) := do
let cache get
match cache.get? e with
| some (lc, prf) =>
@@ -126,7 +126,7 @@ We also transform the expression as we descend into it:
* pushing coercions: `↑(x + y)`, `↑(x * y)`, `↑(x / k)`, `↑(x % k)`, `↑k`
* unfolding `emod`: `x % k` → `x - x / k`
-/
partial def asLinearComboImpl (e : Expr) : OmegaM (LinearCombo × OmegaM Expr × List Expr) := do
partial def asLinearComboImpl (e : Expr) : OmegaM (LinearCombo × OmegaM Expr × Std.HashSet Expr) := do
trace[omega] "processing {e}"
match groundInt? e with
| some i =>
@@ -148,7 +148,7 @@ partial def asLinearComboImpl (e : Expr) : OmegaM (LinearCombo × OmegaM Expr ×
mkEqTrans
( mkAppM ``Int.add_congr #[ prf₁, prf₂])
( mkEqSymm add_eval)
pure (l₁ + l₂, prf, facts₁ ++ facts₂)
pure (l₁ + l₂, prf, facts₁.union facts₂)
| (``HSub.hSub, #[_, _, _, _, e₁, e₂]) => do
let (l₁, prf₁, facts₁) asLinearCombo e₁
let (l₂, prf₂, facts₂) asLinearCombo e₂
@@ -158,7 +158,7 @@ partial def asLinearComboImpl (e : Expr) : OmegaM (LinearCombo × OmegaM Expr ×
mkEqTrans
( mkAppM ``Int.sub_congr #[ prf₁, prf₂])
( mkEqSymm sub_eval)
pure (l₁ - l₂, prf, facts₁ ++ facts₂)
pure (l₁ - l₂, prf, facts₁.union facts₂)
| (``Neg.neg, #[_, _, e']) => do
let (l, prf, facts) asLinearCombo e'
let prf' : OmegaM Expr := do
@@ -184,7 +184,7 @@ partial def asLinearComboImpl (e : Expr) : OmegaM (LinearCombo × OmegaM Expr ×
mkEqTrans
( mkAppM ``Int.mul_congr #[ xprf, yprf])
( mkEqSymm mul_eval)
pure (some (LinearCombo.mul xl yl, prf, xfacts ++ yfacts), true)
pure (some (LinearCombo.mul xl yl, prf, xfacts.union yfacts), true)
else
pure (none, false)
match r? with
@@ -242,7 +242,7 @@ where
Apply a rewrite rule to an expression, and interpret the result as a `LinearCombo`.
(We're not rewriting any subexpressions here, just the top level, for efficiency.)
-/
rewrite (lhs rw : Expr) : OmegaM (LinearCombo × OmegaM Expr × List Expr) := do
rewrite (lhs rw : Expr) : OmegaM (LinearCombo × OmegaM Expr × Std.HashSet Expr) := do
trace[omega] "rewriting {lhs} via {rw} : {← inferType rw}"
match ( inferType rw).eq? with
| some (_, _lhs', rhs) =>
@@ -250,7 +250,7 @@ where
let prf' : OmegaM Expr := do mkEqTrans rw ( prf)
pure (lc, prf', facts)
| none => panic! "Invalid rewrite rule in 'asLinearCombo'"
handleNatCast (e i n : Expr) : OmegaM (LinearCombo × OmegaM Expr × List Expr) := do
handleNatCast (e i n : Expr) : OmegaM (LinearCombo × OmegaM Expr × Std.HashSet Expr) := do
match n with
| .fvar h =>
if let some v h.getValue? then
@@ -297,7 +297,7 @@ where
| (``Fin.val, #[n, x]) =>
handleFinVal e i n x
| _ => mkAtomLinearCombo e
handleFinVal (e i n x : Expr) : OmegaM (LinearCombo × OmegaM Expr × List Expr) := do
handleFinVal (e i n x : Expr) : OmegaM (LinearCombo × OmegaM Expr × Std.HashSet Expr) := do
match x with
| .fvar h =>
if let some v h.getValue? then
@@ -343,11 +343,12 @@ We solve equalities as they are discovered, as this often results in an earlier
-/
def addIntEquality (p : MetaProblem) (h x : Expr) : OmegaM MetaProblem := do
let (lc, prf, facts) asLinearCombo x
let newFacts : List Expr := facts.filter (p.processedFacts.contains · = false)
let newFacts : Std.HashSet Expr := facts.fold (init := ) fun s e =>
if p.processedFacts.contains e then s else s.insert e
trace[omega] "Adding proof of {lc} = 0"
pure <|
{ p with
facts := newFacts ++ p.facts
facts := newFacts.toList ++ p.facts
problem := (p.problem.addEquality lc.const lc.coeffs
(some do mkEqTrans ( mkEqSymm ( prf)) h)) |>.solveEqualities }
@@ -358,11 +359,12 @@ We solve equalities as they are discovered, as this often results in an earlier
-/
def addIntInequality (p : MetaProblem) (h y : Expr) : OmegaM MetaProblem := do
let (lc, prf, facts) asLinearCombo y
let newFacts : List Expr := facts.filter (p.processedFacts.contains · = false)
let newFacts : Std.HashSet Expr := facts.fold (init := ) fun s e =>
if p.processedFacts.contains e then s else s.insert e
trace[omega] "Adding proof of {lc} ≥ 0"
pure <|
{ p with
facts := newFacts ++ p.facts
facts := newFacts.toList ++ p.facts
problem := (p.problem.addInequality lc.const lc.coeffs
(some do mkAppM ``le_of_le_of_eq #[h, ( prf)])) |>.solveEqualities }

View File

@@ -9,7 +9,7 @@ prelude
public import Init.BinderPredicates
public import Init.Data.Int.Order
public import Init.Data.List.MinMax
public import Init.Data.Nat.Order
public import Init.Data.Nat.MinMax
public import Init.Data.Option.Lemmas
public section
@@ -35,10 +35,20 @@ We completely characterize the function via
-/
def nonzeroMinimum (xs : List Nat) : Nat := xs.filter (· 0) |>.min? |>.getD 0
-- A specialization of `minimum?_eq_some_iff` to Nat.
-- This is a duplicate `min?_eq_some_iff'` proved in `Init.Data.List.Nat.Basic`,
-- and could be deduplicated but the import hierarchy is awkward.
theorem min?_eq_some_iff'' {xs : List Nat} :
xs.min? = some a (a xs b xs, a b) :=
min?_eq_some_iff
(le_refl := Nat.le_refl)
(min_eq_or := fun _ _ => Nat.min_def .. by split <;> simp)
(le_min_iff := fun _ _ _ => Nat.le_min)
open Classical in
@[simp] theorem nonzeroMinimum_eq_zero_iff {xs : List Nat} :
xs.nonzeroMinimum = 0 x xs, x = 0 := by
simp [nonzeroMinimum, Option.getD_eq_iff, min?_eq_none_iff, min?_eq_some_iff,
simp [nonzeroMinimum, Option.getD_eq_iff, min?_eq_none_iff, min?_eq_some_iff'',
filter_eq_nil_iff, mem_filter]
theorem nonzeroMinimum_mem {xs : List Nat} (w : xs.nonzeroMinimum 0) :
@@ -46,7 +56,7 @@ theorem nonzeroMinimum_mem {xs : List Nat} (w : xs.nonzeroMinimum ≠ 0) :
dsimp [nonzeroMinimum] at *
generalize h : (xs.filter (· 0) |>.min?) = m at *
match m, w with
| some (m+1), _ => simp_all [min?_eq_some_iff, mem_filter]
| some (m+1), _ => simp_all [min?_eq_some_iff'', mem_filter]
theorem nonzeroMinimum_pos {xs : List Nat} (m : a xs) (h : a 0) : 0 < xs.nonzeroMinimum :=
Nat.pos_iff_ne_zero.mpr fun w => h (nonzeroMinimum_eq_zero_iff.mp w _ m)
@@ -58,7 +68,7 @@ theorem nonzeroMinimum_le {xs : List Nat} (m : a ∈ xs) (h : a ≠ 0) : xs.nonz
generalize h : (xs.filter (· 0) |>.min?) = m? at *
match m?, w with
| some m?, _ => rfl
rw [min?_eq_some_iff] at this
rw [min?_eq_some_iff''] at this
apply this.2
simp [List.mem_filter]
exact m, h

View File

@@ -168,11 +168,11 @@ def mkEqReflWithExpectedType (a b : Expr) : MetaM Expr := do
Analyzes a newly recorded atom,
returning a collection of interesting facts about it that should be added to the context.
-/
def analyzeAtom (e : Expr) : OmegaM (List Expr) := do
def analyzeAtom (e : Expr) : OmegaM (Std.HashSet Expr) := do
match e.getAppFnArgs with
| (``Nat.cast, #[.const ``Int [], _, e']) =>
-- Casts of natural numbers are non-negative.
let mut r := [Expr.app (.const ``Int.ofNat_nonneg []) e']
let mut r := ( : Std.HashSet Expr).insert (Expr.app (.const ``Int.ofNat_nonneg []) e')
match ( cfg).splitNatSub, e'.getAppFnArgs with
| true, (``HSub.hSub, #[_, _, _, _, a, b]) =>
-- `((a - b : Nat) : Int)` gives a dichotomy
@@ -194,8 +194,9 @@ def analyzeAtom (e : Expr) : OmegaM (List Expr) := do
let ne_zero := mkApp3 (.const ``Ne [1]) (.const ``Int []) k (toExpr (0 : Int))
let pos := mkApp4 (.const ``LT.lt [0]) (.const ``Int []) (.const ``Int.instLTInt [])
(toExpr (0 : Int)) k
pure [mkApp3 (.const ``Int.mul_ediv_self_le []) x k ( mkDecideProof ne_zero),
mkApp3 (.const ``Int.lt_mul_ediv_self_add []) x k ( mkDecideProof pos)]
pure <| ( : Std.HashSet Expr).insert
(mkApp3 (.const ``Int.mul_ediv_self_le []) x k ( mkDecideProof ne_zero)) |>.insert
(mkApp3 (.const ``Int.lt_mul_ediv_self_add []) x k ( mkDecideProof pos))
| (``HMod.hMod, #[_, _, _, _, x, k]) =>
match k.getAppFnArgs with
| (``HPow.hPow, #[_, _, _, _, b, exp]) => match natCast? b with
@@ -205,9 +206,10 @@ def analyzeAtom (e : Expr) : OmegaM (List Expr) := do
let b_pos := mkApp4 (.const ``LT.lt [0]) (.const ``Int []) (.const ``Int.instLTInt [])
(toExpr (0 : Int)) b
let pow_pos := mkApp3 (.const ``Lean.Omega.Int.pos_pow_of_pos []) b exp ( mkDecideProof b_pos)
pure [mkApp3 (.const ``Int.emod_nonneg []) x k
(mkApp3 (.const ``Int.ne_of_gt []) k (toExpr (0 : Int)) pow_pos),
mkApp3 (.const ``Int.emod_lt_of_pos []) x k pow_pos]
pure <| ( : Std.HashSet Expr).insert
(mkApp3 (.const ``Int.emod_nonneg []) x k
(mkApp3 (.const ``Int.ne_of_gt []) k (toExpr (0 : Int)) pow_pos)) |>.insert
(mkApp3 (.const ``Int.emod_lt_of_pos []) x k pow_pos)
| (``Nat.cast, #[.const ``Int [], _, k']) =>
match k'.getAppFnArgs with
| (``HPow.hPow, #[_, _, _, _, b, exp]) => match natCast? b with
@@ -218,25 +220,28 @@ def analyzeAtom (e : Expr) : OmegaM (List Expr) := do
(toExpr (0 : Nat)) b
let pow_pos := mkApp3 (.const ``Nat.pos_pow_of_pos []) b exp ( mkDecideProof b_pos)
let cast_pos := mkApp2 (.const ``Int.ofNat_pos_of_pos []) k' pow_pos
pure [mkApp3 (.const ``Int.emod_nonneg []) x k
(mkApp3 (.const ``Int.ne_of_gt []) k (toExpr (0 : Int)) cast_pos),
mkApp3 (.const ``Int.emod_lt_of_pos []) x k cast_pos]
pure <| ( : Std.HashSet Expr).insert
(mkApp3 (.const ``Int.emod_nonneg []) x k
(mkApp3 (.const ``Int.ne_of_gt []) k (toExpr (0 : Int)) cast_pos)) |>.insert
(mkApp3 (.const ``Int.emod_lt_of_pos []) x k cast_pos)
| _ => match x.getAppFnArgs with
| (``Nat.cast, #[.const ``Int [], _, x']) =>
-- Since we push coercions inside `%`, we need to record here that
-- `(x : Int) % (y : Int)` is non-negative.
pure [mkApp2 (.const ``Int.emod_ofNat_nonneg []) x' k]
pure <| ( : Std.HashSet Expr).insert (mkApp2 (.const ``Int.emod_ofNat_nonneg []) x' k)
| _ => pure
| _ => pure
| (``Min.min, #[_, _, x, y]) =>
pure [mkApp2 (.const ``Int.min_le_left []) x y, mkApp2 (.const ``Int.min_le_right []) x y]
pure <| ( : Std.HashSet Expr).insert (mkApp2 (.const ``Int.min_le_left []) x y) |>.insert
(mkApp2 (.const ``Int.min_le_right []) x y)
| (``Max.max, #[_, _, x, y]) =>
pure [mkApp2 (.const ``Int.le_max_left []) x y, mkApp2 (.const ``Int.le_max_right []) x y]
pure <| ( : Std.HashSet Expr).insert (mkApp2 (.const ``Int.le_max_left []) x y) |>.insert
(mkApp2 (.const ``Int.le_max_right []) x y)
| (``ite, #[α, i, dec, t, e]) =>
if α == (.const ``Int []) then
pure [mkApp5 (.const ``ite_disjunction [0]) α i dec t e]
pure <| ( : Std.HashSet Expr).insert <| mkApp5 (.const ``ite_disjunction [0]) α i dec t e
else
pure []
pure {}
| _ => pure
/--
@@ -249,7 +254,7 @@ Return its index, and, if it is new, a collection of interesting facts about the
* for each new atom of the form `((a - b : Nat) : Int)`, the fact:
`b ≤ a ∧ ((a - b : Nat) : Int) = a - b a < b ∧ ((a - b : Nat) : Int) = 0`
-/
def lookup (e : Expr) : OmegaM (Nat × Option (List Expr)) := do
def lookup (e : Expr) : OmegaM (Nat × Option (Std.HashSet Expr)) := do
let c getThe State
let e canon e
match c.atoms[e]? with
@@ -259,7 +264,7 @@ def lookup (e : Expr) : OmegaM (Nat × Option (List Expr)) := do
let facts analyzeAtom e
if isTracingEnabledFor `omega then
unless facts.isEmpty do
trace[omega] "New facts: {← facts.mapM fun e => inferType e}"
trace[omega] "New facts: {← facts.toList.mapM fun e => inferType e}"
let i modifyGetThe State fun c =>
(c.atoms.size, { c with atoms := c.atoms.insert e c.atoms.size })
return (i, some facts)

View File

@@ -1188,8 +1188,9 @@ private def mkSyntheticSorryFor (expectedType? : Option Expr) : TermElabM Expr :
elaboration step with exception `ex`.
-/
def exceptionToSorry (ex : Exception) (expectedType? : Option Expr) : TermElabM Expr := do
let syntheticSorry mkSyntheticSorryFor expectedType?
logException ex
mkSyntheticSorryFor expectedType?
pure syntheticSorry
/-- If `mayPostpone == true`, throw `Exception.postpone`. -/
def tryPostpone : TermElabM Unit := do

View File

@@ -2437,42 +2437,34 @@ def realizeValue [BEq α] [Hashable α] [TypeName α] (env : Environment) (forCo
| none =>
throw <| .userError s!"trying to realize `{TypeName.typeName α}` value but \
`enableRealizationsForConst` must be called for '{forConst}' first"
let res (do
-- First try checking for the key non-atomically as (de)allocating the promise is expensive.
let m ctx.realizeMapRef.get
if let some m' := m.find? (TypeName.typeName α) then
-- Safety: `typeName α` should uniquely identify `PHashMap α (Task Dynamic)`; there are no other
-- accesses to `private realizeMapRef` outside this function.
let m' := unsafe unsafeCast (β := PHashMap α (Task Dynamic)) m'
if let some t := m'[key] then
return t.get
-- Now check atomically.
let prom IO.Promise.new
let existingConsts? ctx.realizeMapRef.modifyGet fun m =>
let m' := match m.find? (TypeName.typeName α) with
| some m' => unsafe unsafeCast (β := PHashMap α (Task Dynamic)) m'
| none => {}
match m'[key] with
| some prom' => (some prom', m)
| none =>
let m' := m'.insert key prom.result!
let m := m.insert (TypeName.typeName α) (unsafe unsafeCast (β := NonScalar) m')
(none, m)
if let some t := existingConsts? then
pure t.get
else
-- safety: `RealizationContext` is private
let realizeEnv : Environment := unsafe unsafeCast ctx.env
let realizeEnv := { realizeEnv with
-- allow realizations to recursively realize other constants for `forConst`. Do note that
-- this allows for recursive realization of `α` itself, which will deadlock.
localRealizationCtxMap := realizeEnv.localRealizationCtxMap.insert forConst ctx
importRealizationCtx? := env.importRealizationCtx?
}
let res realize realizeEnv ctx.opts
prom.resolve res
pure res)
let prom IO.Promise.new
-- atomically check whether we are the first branch to realize `key`
let existingConsts? ctx.realizeMapRef.modifyGet fun m =>
-- Safety: `typeName α` should uniquely identify `PHashMap α (Task Dynamic)`; there are no other
-- accesses to `private realizeMapRef` outside this function.
let m' := match m.find? (TypeName.typeName α) with
| some m' => unsafe unsafeCast (β := PHashMap α (Task Dynamic)) m'
| none => {}
match m'[key] with
| some prom' => (some prom', m)
| none =>
let m' := m'.insert key prom.result!
let m := m.insert (TypeName.typeName α) (unsafe unsafeCast (β := NonScalar) m')
(none, m)
let res if let some t := existingConsts? then
pure t.get
else
-- safety: `RealizationContext` is private
let realizeEnv : Environment := unsafe unsafeCast ctx.env
let realizeEnv := { realizeEnv with
-- allow realizations to recursively realize other constants for `forConst`. Do note that
-- this allows for recursive realization of `α` itself, which will deadlock.
localRealizationCtxMap := realizeEnv.localRealizationCtxMap.insert forConst ctx
importRealizationCtx? := env.importRealizationCtx?
}
let res realize realizeEnv ctx.opts
prom.resolve res
pure res
IO.setNumHeartbeats heartbeats
return res

View File

@@ -1440,9 +1440,7 @@ opaque instantiateRevRange (e : @& Expr) (beginIdx endIdx : @& Nat) (subst : @&
with `xs` ordered from outermost to innermost de Bruijn index.
For example, `e := f x y` with `xs := #[x, y]` goes to `f #1 #0`,
whereas `e := f x y` with `xs := #[y, x]` goes to `f #0 #1`.
Careful, this function does not instantiate assigned meta variables. -/
whereas `e := f x y` with `xs := #[y, x]` goes to `f #0 #1`. -/
@[extern "lean_expr_abstract"]
opaque abstract (e : @& Expr) (xs : @& Array Expr) : Expr
@@ -2383,13 +2381,4 @@ def mkIntLit (n : Int) : Expr :=
def reflBoolTrue : Expr :=
mkApp2 (mkConst ``Eq.refl [levelOne]) (mkConst ``Bool) (mkConst ``Bool.true)
def reflBoolFalse : Expr :=
mkApp2 (mkConst ``Eq.refl [levelOne]) (mkConst ``Bool) (mkConst ``Bool.false)
def eagerReflBoolTrue : Expr :=
mkApp2 (mkConst ``eagerReduce [0]) (mkApp3 (mkConst ``Eq [1]) (mkConst ``Bool) (mkConst ``Bool.true) (mkConst ``Bool.true)) reflBoolTrue
def eagerReflBoolFalse : Expr :=
mkApp2 (mkConst ``eagerReduce [0]) (mkApp3 (mkConst ``Eq [1]) (mkConst ``Bool) (mkConst ``Bool.false) (mkConst ``Bool.false)) reflBoolFalse
end Lean

Some files were not shown because too many files have changed in this diff Show More