GithubHelp home page GithubHelp logo

std4's Introduction

std4

Work in progress standard library for Lean 4. This is a collection of data structures and tactics intended for use by both computer-science applications and mathematics applications of Lean 4.

Using std4

To use std4 in your project, add the following to your lakefile.lean:

require std from git "https://github.com/leanprover/std4" @ "main"

Additionally, please make sure that you're using the version of Lean that the current version of std4 expects. The easiest way to do this is to copy the lean-toolchain file from this repository to your project. Once you've added the dependency declaration, the command lake update checks out the current version of std4 and writes it the Lake manifest file. Don't run this command again unless you're prepared to potentially also update your Lean compiler version, as it will retrieve the latest version of dependencies and add them to the manifest.

Build instructions

  • Get the newest version of elan. If you already have installed a version of Lean, you can run
    elan self update
    
    If the above command fails, or if you need to install elan, run
    curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh
    
    If this also fails, follow the instructions under Regular install here.
  • To build std4 run lake build. To build and run all tests, run make.
  • If you added a new file, run the command scripts/updateStd.sh to update the imports.

Documentation

You can generate std4's documentation with

# if you're generating documentation for the first time
> lake -R -Kdoc=on update
...
# actually generate the documentation
> lake -R -Kdoc=on build Std:docs
...
> ls build/doc/index.html
build/doc/index.html

After generating the docs, run lake build -R to reset the configuration.

The top-level HTML file will be located at build/doc/Std.html, though to actually expose the documentation as a server you need to

> cd build/doc
> python3 -m http.server
Serving HTTP on :: port 8000 (http://[::]:8000/) ...

Note that documentation for the latest nightly of std4 is available as part of the Mathlib 4 documentation.

Contributing

Every pull request should have exactly one of the status labels awaiting-review, awaiting-author or WIP (in progress). To change the status label of a pull request, add a comment containing one of these options and nothing else. This will remove the previous label and replace it by the requested status label.

One of the easiest ways to contribute is to find a missing proof and complete it. The proof_wanted declaration documents statements that have been identified as being useful, but that have not yet been proven.

In contrast to mathlib, std uses pull requests from forks of this repository. Hence, no special permissions on this repository are required for new contributors.

You can change the labels on PRs by commenting one of awaiting-review, awaiting-author, or WIP. This is helpful for triage.

std4's People

Contributors

adrienchampion avatar alexjbest avatar alexkeizer avatar bollu avatar chabulhwi avatar david-christiansen avatar digama0 avatar dupuisf avatar eric-wieser avatar fgdorais avatar gebner avatar hrmacbeth avatar jamesgallicchio avatar jlimperg avatar joehendrix avatar kmill avatar komyyy avatar leodemoura avatar mo271 avatar negiizhao avatar nomeata avatar patrickmassot avatar ruben-vandevelde avatar rwbarton avatar semorrison avatar thorimur avatar timotree3 avatar tobiasgrosser avatar urkud avatar vtec234 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

std4's Issues

by_contra doesn't work if goal is an implication

Consider this example:

example (P : Prop) : P → P := by
  by_contra

The by_contra tactic fails. I think the problem can be fixed by changing apply byContradiction to refine byContradiction ?_.

`omega` does not support powers.

import Std.Tactic.Omega

example (b : Nat) (h : b = 1 ^ 2) : b = 1 := by
  -- omega -- omega did not find a contradiction: trivial
  change b = 1 at h
  omega

example (b : Nat) (h : b = 2 ^ 1) : b = 2 := by
  -- omega -- omega did not find a contradiction: [0, 1] ∈ [0, 1]
  change b = 2 at h
  omega

My understanding is that this is out of scope, and instead omega would be improved by a hook into norm_num.

incorrect output from `linter.unnecessarySimpa`

import Std.Tactic.Simpa

theorem foo : ℕ = ℤ ↔ False := sorry

example (bar : ℕ = ℤ) : False := by
  simpa [foo] using bar
/-
try 'simp at bar' instead of 'simpa using bar' [linter.unnecessarySimpa]
-/

The linter is correct in that simpa can be avoided, but its suggestion is not correct; it should be suggesting simp [foo] at bar (which works). simp at bar does not close the goal.

overzealous simpComm linter?

import Std.Tactic.Lint

def SemiconjBy [Mul M] (a x y : M) : Prop :=
  a * x = y * a

structure MulOpposite (α : Type u) : Type u where
  op :: unop : α

postfix:max "ᵐᵒᵖ" => MulOpposite

namespace MulOpposite

instance [Mul α] : Mul αᵐᵒᵖ where mul x y := op (unop y * unop x)

@[simp]
theorem unop_inj {x y : αᵐᵒᵖ} : unop x = unop y ↔ x = y := by
  cases x; cases y; simp

@[simp]
theorem semiconj_by_unop [Mul α] {a x y : αᵐᵒᵖ} :
    SemiconjBy (unop a) (unop y) (unop x) ↔ SemiconjBy a x y := sorry

end MulOpposite

#lint only simpComm
/- The `simpComm` linter reports:
COMMUTATIVITY LEMMA IS SIMP.
Some commutativity lemmas are simp lemmas: -/
-- Mathlib.scratch.scratch1
#check @MulOpposite.unop_inj /- should not be marked simp -/
#check @MulOpposite.semiconj_by_unop /- should not be marked simp -/

As reported on Zulip here and more discussion here. For now I'm just marking the declarations with nolint.

For completeness, here's the corresponding Lean 3 code, which lints:

-- lean 3
import tactic.lint

variable {α : Type*}

universe u

def SemiconjBy [has_mul α] (a x y : α) : Prop :=
  a * x = y * a

structure mul_opposite (α : Type u) : Type u :=
  op :: (unop : α)

postfix `ᵐᵒᵖ`:std.prec.max_plus := mul_opposite

namespace mul_opposite

instance [has_mul α] : has_mul αᵐᵒᵖ := ⟨λ x y, op (unop y * unop x)⟩

@[simp]
theorem unop_inj {x y : αᵐᵒᵖ} : unop x = unop y ↔ x = y := by
  cases x; cases y; simp

@[simp]
theorem semiconj_by_unop [has_mul α] {a x y : αᵐᵒᵖ} :
    SemiconjBy (unop a) (unop y) (unop x) ↔ SemiconjBy a x y := sorry

end mul_opposite

#lint

`omega` doesn't understand `n ≠ 0`

omega doesn't understand that, for n : ℕ, 0 < n is the same as n ≠ 0:

import Mathlib.Data.Nat.Order.Basic

-- A true lemma
lemma right {t i : ℕ} (t0 : t ≠ 0) (h : i < 64) : i + t - 64 < t := by
  simp only [add_comm _ t, ←tsub_tsub_eq_add_tsub_of_le h.le, imp_false, not_le]
  apply Nat.sub_lt (Nat.pos_of_ne_zero t0) (Nat.sub_pos_of_lt h)

-- `omega` fails to prove it
lemma wrong {t i : ℕ} (t0 : t ≠ 0) (h : i < 64) : i + t - 64 < t := by omega

-- `omega` works if we use `0 <` instead of `≠ 0`
lemma better {t i : ℕ} (t0 : 0 < t) (h : i < 64) : i + t - 64 < t := by omega

Zulip thread

`omega` fails when an extra divisibility hypothesis is added

import Std.Tactic.Omega

theorem foo
    {i : Nat}
    (h1 : i < 330)
    (h2 : 7 ∣ (660 + i) * (1319 - i)) -- comment this out, and omega succeeds!
    : 1319 - i < 1979 := by
  omega
  -- omega did not find a contradiction:
  -- [0, 1] ∈ [1979, ∞)
  -- [1] ∈ [0, 329

Array.minX functions are buggy

There are two basic bugs: the default value of minD is always used and compared against all entries in the array, instead of only being used as default value if the array is empty:

#eval #[1, 2, 3].minD 0

Expected: 1, actual: 0.

And the case that startPos <= endPos should signify an empty range is not considered:

#eval #[1, 2, 3].min? 1 0

Expected: none, actual: some 2.

`simpNF` should use dsimp for lemmas proved by `rfl`

The @[simp] attribute is used by both simp and dsimp, so it is possible for a rfl lemma to have a proof by simp but not one by dsimp, and so this is a false positive. The linter should check if the current declaration is a rfl lemma and if so restrict its attention to dsimp proofs.

Build fails: Failed to syntesize instance

Dearest community,
I have a fresh install of elan (from the VS code extension on Windows), and I'm unable to get lean running due to the following error:

`c:\Users\.....\.elan\toolchains\leanprover--lean4---stable\bin\lake.exe print-paths Init MIL.Common` failed:

stderr:
info: [148/1402] Building Std.Tactic.Simpa
info: [172/1485] Building Std.CodeAction.Misc
info: [172/1485] Building Std.CodeAction.Deprecated
info: [173/1490] Building Std.Tactic.GuardMsgs
info: [176/1518] Building Std.Tactic.SimpTrace
info: [183/1556] Building Std.Tactic.Lint.TypeClass
info: [183/1562] Building Std.Tactic.Lint.Misc
info: [204/1701] Building Std.Tactic.Lint
error: > LEAN_PATH=.\lake-packages\std\build\lib;.\lake-packages\Qq\build\lib;.\lake-packages\aesop\build\lib;.\lake-packages\Cli\build\lib;.\lake-packages\proofwidgets\build\lib;.\lake-packages\mathlib\build\lib;.\lake-packages\mil\build\lib;.\build\lib PATH c:\Users\......\.elan\toolchains\leanprover--lean4---stable\bin\lean.exe -Dlinter.missingDocs=true -DwarningAsError=true .\lake-packages\std\.\.\Std\Tactic\SimpTrace.lean -R .\lake-packages\std\.\. -o .\lake-packages\std\build\lib\Std\Tactic\SimpTrace.olean -i .\lake-packages\std\build\lib\Std\Tactic\SimpTrace.ilean -c .\lake-packages\std\build\ir\Std\Tactic\SimpTrace.c
error: stdout:
.\lake-packages\std\.\.\Std\Tactic\SimpTrace.lean:51:6: error: function expected at
  Origin.decl declName
term has type
  Origin
.\lake-packages\std\.\.\Std\Tactic\SimpTrace.lean:72:12: error: failed to synthesize instance
  HAppend (Array (TSyntax `Lean.Parser.Tactic.simpStar)) (Array (TSyntax `Lean.Parser.Tactic.simpLemma))
    (Array (TSyntax `Lean.Parser.Tactic.simpStar))
error: external command `c:\Users\......\.elan\toolchains\leanprover--lean4---stable\bin\lean.exe` exited with code 1
info: [210/1701] Building Std.Tactic.Alias
info: [211/1701] Building Std.CodeAction
error: > LEAN_PATH=.\lake-packages\std\build\lib;.\lake-packages\Qq\build\lib;.\lake-packages\aesop\build\lib;.\lake-packages\Cli\build\lib;.\lake-packages\proofwidgets\build\lib;.\lake-packages\mathlib\build\lib;.\lake-packages\mil\build\lib;.\build\lib PATH c:\Users\.....\.elan\toolchains\leanprover--lean4---stable\bin\lean.exe -Dlinter.missingDocs=true -DwarningAsError=true .\lake-packages\std\.\.\Std\Tactic\Simpa.lean -R .\lake-packages\std\.\. -o .\lake-packages\std\build\lib\Std\Tactic\Simpa.olean -i .\lake-packages\std\build\lib\Std\Tactic\Simpa.ilean -c .\lake-packages\std\build\ir\Std\Tactic\Simpa.c
error: stdout:
.\lake-packages\std\.\.\Std\Tactic\Simpa.lean:74:6: error: function expected at
  Origin.decl declName
term has type
  Origin
.\lake-packages\std\.\.\Std\Tactic\Simpa.lean:103:12: error: failed to synthesize instance
  HAppend (Array (TSyntax `Lean.Parser.Tactic.simpStar)) (Array (TSyntax `Lean.Parser.Tactic.simpLemma))
    (Array (TSyntax `Lean.Parser.Tactic.simpStar))
error: external command `c:\Users\.....\.elan\toolchains\leanprover--lean4---stable\bin\lean.exe` exited with code 1

I've tried manually switching to nightly, and get the same result. I get no errors if I run lake update; lake build in the terminal.
Can anyone give me some pointers to what I'm doing wrong?
Thanks in advance!

Documentation instructions are out of date.

The README has the build instructions

# if you're generating documentation for the first time
> lake -Kdoc=on update
...
# actually generate the documentation
> lake -Kdoc=on build Std:docs
...
> ls build/doc/index.html
build/doc/index.html

The instruction lake -Kdoc=on build Std:docs reports the error:

error: unknown library facet `docs`

We should ensure documentation can be built and update the README.

show_term auto bound interaction and by?

def t : {a : Nat} → Nat :=
by
  intro X
  sorry

works, but

def t : {a : Nat} → Nat :=
show_term by
  intro X
  sorry

auto introduces a as it is a term now and so breaks the proof.

Does this mean that the implementation of rw? should rather be as rw show_term instead of the other way around. I can't think of a downside but I'm not sure

Bug: `simp?` does not take reverse directions into account

MWE:

import Std
def foo : Nat → Nat := sorry
theorem foo_eq_iff (z : Nat) : z = 17 ↔ foo z = 3 := sorry
theorem fail (z : Nat) (h : z = 17) : foo z = 3 := by
  simp? [← foo_eq_iff]
  exact h

The simp? works fine, but the suggestion is to use simp only [foo_eq_iff].

over-zealous `cases` code action

This code

import Mathlib.Tactic

inductive Relation (n : ℕ) : ℕ → ℕ → Prop

example {x y z} (r : Relation x y z) : true := by
  cases r

followed by clicking the lightbulb and selecting "Generate an explicit pattern match for rcases" gives me the exciting output

example {x y z} (r : Relation x y z) : true := by
  cases r with
  | n => sorry
  | [email protected]._hyg.6 => sorry
  | [email protected]._hyg.10 => sorry

Examples of this showing up in the wild: here, here (including MWE), here.

`simpNF` linter rejecting working simp lemma

import Std.Tactic.Lint

def Set (α : Type u) := α → Prop

def unionᵢ (s : ι → Set β) : Set β := sorry
--  supᵢ s

def interᵢ (s : ι → Set β) : Set β := sorry

@[simp]
theorem unionᵢ_interᵢ_ge_nat_add (f : Nat → Set α) (k : Nat) :
    unionᵢ (λ n => interᵢ (λ i => interᵢ (λ (_h : i ≥ n) => f (i + k)))) =
    unionᵢ (λ n => interᵢ (λ i => interᵢ (λ (_h : i ≥ n) => f i))) := sorry

example (f : Nat → Set α) (k : Nat) :
    unionᵢ (λ n => interᵢ (λ i => interᵢ (λ (_h : i ≥ n) => f (i + k)))) =
    unionᵢ (λ n => interᵢ (λ i => interᵢ (λ (_h : i ≥ n) => f i))) := by simp -- works

#lint only simpNF
/- The `simpNF` linter reports:
SOME SIMP LEMMAS ARE NOT IN SIMP-NORMAL FORM.
see note [simp-normal form] for tips how to debug this.
https://leanprover-community.github.io/mathlib_docs/notes.html#simp-normal%20form -/
#check @unionᵢ_interᵢ_ge_nat_add /- Left-hand side does not simplify, when using the simp lemma on itself.
This usually means that it will never apply.
 -/

Is the linter misfiring? The simp lemma does seem to apply. Discussions here (about the corresponding lattice lemma) and here (about the lemma above). Note in particular Gabriel's comment. The lemma is usually written (⋃ n, ⋂ i ≥ n, f (i + k)) = ⋃ n, ⋂ i ≥ n, f i but I didn't want to use notation3 in the MWE. Note also that Gabriel suggests this shouldn't be a simp lemma anyway but I thought I'd record the issue anyway.

Document std4#232

This was a really useful addition which allows any user to update awaiting-review, awaiting-author and WIP labels. Since it's especially useful for first-time contributors, there should be documentation somewhere. Maybe I missed something but I couldn't find it.

Add docker / gitpod integrations

Mathlib has .docker and .devcontainer folders that (for one thing) make it easy to quickly load in to a fresh install of lean + mathlib (eg with gitpod.io). I think adding these to Std would be helpful

rcases doesn't seem to support ?_ placeholders

import Std.Tactic.RCases

theorem aux (h : 0 < 2) : ∃ n : Nat, n = 2 := ⟨2, rfl⟩

example : True := by
  rcases aux ?_ with ⟨x, h⟩
  trivial

I would expect a side goal to be created (like in lean3), but get "don't know how to synthesize placeholder for argument 'h'"

Codify style guide

To ease new contributions, we should write down the style rules (indentation, usage of trailing punctuation and structuring tactics) so that we have a place to point contributors to. Currently the most complete source of this information is the lean pretty printer, but this also has many bugs or issues that we were not able to fix directly in the pretty printer architecture, and mathlib maintains some scripts to address shortcomings in the pretty printer.

Automate testing against Mathlib?

This repo is upstream from Mathlib, but we'd like to ensure changes to main do not break Mathlib.

Should we add a build step or task that builds Mathlib (perhaps storing the relevant Mathlib version in a file here (e.g., .github/mathlib_test_version)?

I'm not sure of the exact policy; perhaps main commits that break mathlib are allowed if a Mathlib PR that fixes the issues is approved?

Hopefully it would not be needed, but if this slows things down, we could potentially add a staging branch (devel) for changes that are accepted by std4 maintainers, but too disruptive for Mathlib to accept right now.

Fixed width signed integer datatypes.

Lean should provide Int8, Int16, Int32 and Int64 to complement UInt8, UInt16, UInt32, and UInt64.

Ideally the definitions should be in core and the compiler extended to generate efficient code for them, but Std may need to provide additional lemma support.

simpNF linter does not handle conditional simp lemmas correctly

The linter fails here, but I claim it should succeed:

import Std

@[simp] theorem cast_fin_h {n m : Nat} (h : m = n) (a : Fin (m + 2)) : (cast (by rw [h]) a : Fin (n + 2)) = (a : Nat) := by cases h; rfl

#lint
#check @cast_fin_h /- Left-hand side does not simplify, when using the simp lemma on itself.
This usually means that it will never apply.
 -/

-- but `simp` works just fine
example {n m : Nat} (h : m = n) (a : Fin (m + 2)) : (cast (by rw [h]) a : Fin (n + 2)) = (a : Nat) := by
  simp [h]

I think this code is falsely concluding that this is not a conditional simp lemma:

/-- Given the list of hypotheses, is this a conditional rewrite rule? -/
def isConditionalHyps (lhs : Expr) : List Expr → MetaM Bool
| [] => pure false
| h :: hs => do
let ldecl ← getFVarLocalDecl h
if !ldecl.binderInfo.isInstImplicit
&& !(← hs.anyM fun h' =>
return (← inferType h').consumeTypeAnnotations.containsFVar h.fvarId!)
&& !lhs.containsFVar h.fvarId! then
return true
isConditionalHyps lhs hs

The check for "appears on the LHS" should not visit Prop subexpressions, as those aren't found by unification.

Cover `mathlib` theorems for `RBMap`

bug: MVarId.isIndependentOf doesn't check local context.

Lean.MVarId.isIndependentOf doesn't check the local context of an mvar and this leads to it missing dependencies.

Here's a file for demonstrating the issue that uses a tactic check_indep to print out the independence result and the local context.

This could perhaps be fixed with a documentation update about it's limitations, but it is not clear if that is sufficient for it's actual use.

import Std.Tactic.PermuteGoals

open Lean Meta Elab.Tactic

elab "check_indep" : tactic => do
  match ← getGoals with
  | [] => throwError "Expected goal"
  | g :: l =>
    let res := if ←g.isIndependentOf l then "" else "not "
    let t ← instantiateMVars (← g.getType)
    IO.println f!"{←ppExpr (.mvar g)} : {←ppExpr t} is {res}independent of:"
    l.forM fun g' => do
      IO.println f!"  {←ppExpr (.mvar g')} : {←ppExpr (← g'.getType)}"
      let ppD (l : LocalDecl) : TacticM PUnit := do
        IO.println f!"    {←ppExpr (.fvar l.fvarId)} : {←ppExpr l.type}"
      let _ ← (←g'.getDecl).lctx.forM ppD
      pure ()

-- It correctly infers this one.
example : ∃ (n : Nat), ∀(x : Fin n), x.val = 0 := by
  apply Exists.intro
  intro x
  swap
  check_indep
  exact 0
  revert x
  intro ⟨x, lt⟩
  contradiction

-- It incorrectly infers this one since the coupling between x.val and y
-- is via an assumption.
example : ∃ (n : Nat), ∀(x : Fin n) (y : Nat), x.val = y → y = 0 := by
  apply Exists.intro
  intro x y p
  swap
  check_indep
  exact 0
  revert x
  intro ⟨x, lt⟩
  contradiction

I discovered this when working on #423.

docBlame linter requires docstrings on propositional structure fields

The following structure:

/-- A bundled version of `n ≠ 0`.  -/
structure NeZero {R} [Zero R] (n : R) : Prop where
  out : n ≠ 0

gives a complaint by the docBlame linter because the def NeZero.out has no docstring.

The annoyance here is that morally NeZero.out is a theorem and so should be immune to docBlame, but core generates it as a def anyway.

I would argue that the docBlame linter should ignore this case, and it should be picked up by the (disabled-by-default) docBlameThm linter instead.

Bugs in `ext` tactic

These bugs were noticed in the discussion of #611.

The .ext and .ext_iff lemmas generated by applying the @[ext] attribute to a structure has sub-optimal binders. For example:

@[ext] structure S (α β) where (a : α) (b : β)
/-
S.ext.{u_1, u_2} {α : Sort u_1} {β : Sort u_2} (x y : S α β) (a : x.a = y.a) (b : x.b = y.b) : x = y
-/
#check S.ext

One would expect x y to be implicit parameters.

The @[local ext]/@[scoped ext] variants don't work correctly when applied to structures.

  • The generated .ext lemma is marked plain @[ext] instead of @[local ext]/@[scoped ext].
  • The .ext and .ext_iff are unconditionally generated, which fails if the lemmas were already generated by an unrelated @[local ext] in a a dependency, for example.

Usage examples for HashMap.lean

Currently the HashMap docs have no code examples. We should have examples similar to those from Std.Data.List.Basic:

/--
Split a list at every occurrence of a separator element. The separators are not in the result.
```
[1, 1, 2, 3, 2, 4, 4].splitOn 2 = [[1, 1], [3], [4, 4]]
```
-/
@[inline] def splitOn [BEq α] (a : α) (as : List α) : List (List α) := as.splitOnP (· == a)

fileExists or pathExists

This is ugly, a friendly wrapper in the same namespace as IO.FS.readFile would be nice. Something like this:

def fileExists (p : FilePath) : BaseIO Bool :=
  return (← p.metadata.toBaseIO).toBool

False positive from the unusedHavesSuffices linter

import Std

/---/
def npowRec {M : Type} [Mul M] (one : M) : Nat → M → M
  | 0, _ => one
  | n + 1, a => a * npowRec one n a

/---/
@[nolint unusedArguments]
abbrev npowRec' {M : Type} [Mul M] (one : M) (_mul_one : ∀ m : M, m * one = m) (_one_mul : ∀ m : M, one * m = m) (k : Nat) (m : M) : M :=
  npowRec one k m

@[nolint unusedArguments]
theorem npowRec'_two_mul {M : Type} [Mul M] (one : M)
    (mul_one : ∀ m : M, m * one = m) (one_mul : ∀ m : M, one * m = m) (k : Nat) (m : M) :
    npowRec' one mul_one one_mul (2 * k) m = npowRec' one mul_one one_mul k (m * m) := sorry

/---/
@[nolint unusedArguments]
def npowBinRec {M : Type} [Mul M] (one : M) (_unused : one * one = one) (_unused' : one * one = one) (k : Nat) (m : M) : M :=
  go k one m
where
  /-- Auxiliary tail-recursive implementation for `npowBinRec`-/
  go : Nat → M → M → M
  | 0, y, _ => y
  | (k + 1), y, x =>
    let k' := (k + 1) >>> 1
    if k &&& 1 = 1 then
      have : k' < k + 1 := Nat.div_lt_self (Nat.zero_lt_succ _) (Nat.lt_succ_self _)
      go k' y (x * x)
    else
      have : k' < k + 1 := Nat.div_lt_self (Nat.zero_lt_succ _) (Nat.lt_succ_self _)
      go k' (y * x) (x * x)
  termination_by go k _ _ => k

theorem npowBinRec.go_spec {M : Type} [Mul M] (one : M) (mul_one : ∀ m : M, m * one = m) (one_mul : ∀ m : M, one * m = m) (k : Nat) (x y : M) :
    npowBinRec.go k y x = y * npowRec' one mul_one one_mul k x := by
  induction k using Nat.strongInductionOn generalizing x y with
  | ind k' ih =>
    cases k' with
    | zero => sorry
    | succ k' =>
      rw [go]
      sorry

#lint

Somehow when we rw [go], the unusedHavesSuffices linter can see the have statements from inside the go, and doesn't like them. This is from leanprover-community/mathlib4#8885

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.