File: Mathlib/Tactic/NormNum/Core.lean

full_name: norm_num
code: /-- Attribute for identifying `norm_num` extensions. -/
syntax (name := norm_num) "norm_num " term,+ : attr
goal: Lean.ParserDescr

full_name: Mathlib.Meta.NormNum.initFn._@.Mathlib.Tactic.NormNum.Core._hyg.34
code: initialize registerTraceClass `Tactic.norm_num
goal: IO Unit

full_name: Mathlib.Meta.NormNum.NormNumExt
code: /--
An extension for `norm_num`.
-/
structure NormNumExt where
  /-- The extension should be run in the `pre` phase when used as simp plugin. -/
  pre := true
  /-- The extension should be run in the `post` phase when used as simp plugin. -/
  post := true
  /-- Attempts to prove an expression is equal to some explicit number of the relevant type. -/
  eval {u : Level} {α : Q(Type u)} (e : Q($α)) : MetaM (Result e)
  /-- The name of the `norm_num` extension. -/
  name : Name := by exact decl_name%
goal: Type

full_name: Mathlib.Meta.NormNum.NormNumExt.pre
code: /--
An extension for `norm_num`.
-/
structure NormNumExt where
  /-- The extension should be run in the `pre` phase when used as simp plugin. -/
  pre := true
  /-- The extension should be run in the `post` phase when used as simp plugin. -/
  post := true
  /-- Attempts to prove an expression is equal to some explicit number of the relevant type. -/
  eval {u : Level} {α : Q(Type u)} (e : Q($α)) : MetaM (Result e)
  /-- The name of the `norm_num` extension. -/
  name : Name := by exact decl_name%
goal: Bool

full_name: Mathlib.Meta.NormNum.NormNumExt.eval
code: /--
An extension for `norm_num`.
-/
structure NormNumExt where
  /-- The extension should be run in the `pre` phase when used as simp plugin. -/
  pre := true
  /-- The extension should be run in the `post` phase when used as simp plugin. -/
  post := true
  /-- Attempts to prove an expression is equal to some explicit number of the relevant type. -/
  eval {u : Level} {α : Q(Type u)} (e : Q($α)) : MetaM (Result e)
  /-- The name of the `norm_num` extension. -/
  name : Name := by exact decl_name%
goal: Lean.MetaM (Mathlib.Meta.NormNum.Result e)

full_name: Mathlib.Meta.NormNum.NormNumExt.name
code: /--
An extension for `norm_num`.
-/
structure NormNumExt where
  /-- The extension should be run in the `pre` phase when used as simp plugin. -/
  pre := true
  /-- The extension should be run in the `post` phase when used as simp plugin. -/
  post := true
  /-- Attempts to prove an expression is equal to some explicit number of the relevant type. -/
  eval {u : Level} {α : Q(Type u)} (e : Q($α)) : MetaM (Result e)
  /-- The name of the `norm_num` extension. -/
  name : Name := by exact decl_name%
goal: Lean.Name

full_name: Mathlib.Meta.NormNum.NormNumExt.post
code: /--
An extension for `norm_num`.
-/
structure NormNumExt where
  /-- The extension should be run in the `pre` phase when used as simp plugin. -/
  pre := true
  /-- The extension should be run in the `post` phase when used as simp plugin. -/
  post := true
  /-- Attempts to prove an expression is equal to some explicit number of the relevant type. -/
  eval {u : Level} {α : Q(Type u)} (e : Q($α)) : MetaM (Result e)
  /-- The name of the `norm_num` extension. -/
  name : Name := by exact decl_name%
goal: Bool

full_name: Mathlib.Meta.NormNum.mkNormNumExt
code: /-- Read a `norm_num` extension from a declaration of the right type. -/
def mkNormNumExt (n : Name) : ImportM NormNumExt 
goal: Lean.ImportM Mathlib.Meta.NormNum.NormNumExt

full_name: Mathlib.Meta.NormNum.Entry
code: /-- Each `norm_num` extension is labelled with a collection of patterns
which determine the expressions to which it should be applied. -/
abbrev Entry 
goal: Type

full_name: Mathlib.Meta.NormNum.NormNums
code: /-- The state of the `norm_num` extension environment -/
structure NormNums where
  /-- The tree of `norm_num` extensions. -/
  tree : DiscrTree NormNumExt := {}
  /-- Erased `norm_num`s. -/
  erased : PHashSet Name := {}
  deriving Inhabited
goal: Type

full_name: Mathlib.Meta.NormNum.NormNums.erased
code: /-- The state of the `norm_num` extension environment -/
structure NormNums where
  /-- The tree of `norm_num` extensions. -/
  tree : DiscrTree NormNumExt := {}
  /-- Erased `norm_num`s. -/
  erased : PHashSet Name := {}
  deriving Inhabited
goal: Lean.PHashSet Lean.Name

full_name: Mathlib.Meta.NormNum.NormNums.tree
code: /-- The state of the `norm_num` extension environment -/
structure NormNums where
  /-- The tree of `norm_num` extensions. -/
  tree : DiscrTree NormNumExt := {}
  /-- Erased `norm_num`s. -/
  erased : PHashSet Name := {}
  deriving Inhabited
goal: Lean.Meta.DiscrTree Mathlib.Meta.NormNum.NormNumExt

full_name: Mathlib.Meta.NormNum.instInhabitedNormNums
code: /-- The state of the `norm_num` extension environment -/
structure NormNums where
  /-- The tree of `norm_num` extensions. -/
  tree : DiscrTree NormNumExt := {}
  /-- Erased `norm_num`s. -/
  erased : PHashSet Name := {}
  deriving Inhabited
goal: Inhabited Mathlib.Meta.NormNum.NormNums

full_name: Mathlib.Meta.NormNum.discrTreeConfig
code: /-- Configuration for `DiscrTree`. -/
def discrTreeConfig : WhnfCoreConfig 
goal: Lean.Meta.WhnfCoreConfig

full_name: Mathlib.Meta.NormNum.normNumExt
code: /-- Environment extensions for `norm_num` declarations -/
initialize normNumExt : ScopedEnvExtension Entry (Entry × NormNumExt) NormNums ←
  -- we only need this to deduplicate entries in the DiscrTree
  have : BEq NormNumExt := ⟨fun _ _ ↦ false⟩
  /- Insert `v : NormNumExt` into the tree `dt` on all key sequences given in `kss`. -/
  let insert kss v dt := kss.foldl (fun dt ks ↦ dt.insertCore ks v) dt
  registerScopedEnvExtension {
    mkInitial := pure {}
    ofOLeanEntry := fun _ e@(_, n) ↦ return (e, ← mkNormNumExt n)
    toOLeanEntry := (·.1)
    addEntry := fun { tree, erased } ((kss, n), ext) ↦
      { tree := insert kss ext tree, erased := erased.erase n }
  }
goal: Lean.ScopedEnvExtension Mathlib.Meta.NormNum.Entry (Mathlib.Meta.NormNum.Entry × Mathlib.Meta.NormNum.NormNumExt)
  Mathlib.Meta.NormNum.NormNums

full_name: Mathlib.Meta.NormNum.initFn._@.Mathlib.Tactic.NormNum.Core._hyg.283
code: /-- Environment extensions for `norm_num` declarations -/
initialize normNumExt : ScopedEnvExtension Entry (Entry × NormNumExt) NormNums ←
  -- we only need this to deduplicate entries in the DiscrTree
  have : BEq NormNumExt := ⟨fun _ _ ↦ false⟩
  /- Insert `v : NormNumExt` into the tree `dt` on all key sequences given in `kss`. -/
  let insert kss v dt := kss.foldl (fun dt ks ↦ dt.insertCore ks v) dt
  registerScopedEnvExtension {
    mkInitial := pure {}
    ofOLeanEntry := fun _ e@(_, n) ↦ return (e, ← mkNormNumExt n)
    toOLeanEntry := (·.1)
    addEntry := fun { tree, erased } ((kss, n), ext) ↦
      { tree := insert kss ext tree, erased := erased.erase n }
  }
goal: IO
  (Lean.ScopedEnvExtension Mathlib.Meta.NormNum.Entry (Mathlib.Meta.NormNum.Entry × Mathlib.Meta.NormNum.NormNumExt)
    Mathlib.Meta.NormNum.NormNums)

full_name: Mathlib.Meta.NormNum.derive
code: /-- Run each registered `norm_num` extension on an expression, returning a `NormNum.Result`. -/
def derive {α : Q(Type u)} (e : Q($α)) (post := false) : MetaM (Result e) 
goal: Lean.MetaM (Mathlib.Meta.NormNum.Result e)

full_name: Mathlib.Meta.NormNum.deriveNat
code: /-- Run each registered `norm_num` extension on a typed expression `e : α`,
returning a typed expression `lit : ℕ`, and a proof of `isNat e lit`. -/
def deriveNat {α : Q(Type u)} (e : Q($α))
    (_inst : Q(AddMonoidWithOne $α) := by with_reducible assumption) :
    MetaM ((lit : Q(ℕ)) × Q(IsNat $e $lit)) 
goal: Lean.MetaM ((lit : Q(ℕ)) × Q(Mathlib.Meta.NormNum.IsNat «$e» «$lit»))

full_name: Mathlib.Meta.NormNum.deriveInt
code: /-- Run each registered `norm_num` extension on a typed expression `e : α`,
returning a typed expression `lit : ℤ`, and a proof of `IsInt e lit` in expression form. -/
def deriveInt {α : Q(Type u)} (e : Q($α))
    (_inst : Q(Ring $α) := by with_reducible assumption) :
    MetaM ((lit : Q(ℤ)) × Q(IsInt $e $lit)) 
goal: Lean.MetaM ((lit : Q(ℤ)) × Q(Mathlib.Meta.NormNum.IsInt «$e» «$lit»))

full_name: Mathlib.Meta.NormNum.deriveRat
code: /-- Run each registered `norm_num` extension on a typed expression `e : α`,
returning a rational number, typed expressions `n : ℤ` and `d : ℕ` for the numerator and
denominator, and a proof of `IsRat e n d` in expression form. -/
def deriveRat {α : Q(Type u)} (e : Q($α))
    (_inst : Q(DivisionRing $α) := by with_reducible assumption) :
    MetaM (ℚ × (n : Q(ℤ)) × (d : Q(ℕ)) × Q(IsRat $e $n $d)) 
goal: Lean.MetaM (ℚ × (n : Q(ℤ)) × (d : Q(ℕ)) × Q(Mathlib.Meta.NormNum.IsRat «$e» «$n» «$d»))

full_name: Mathlib.Meta.NormNum.deriveBool
code: /-- Run each registered `norm_num` extension on a typed expression `p : Prop`,
and returning the truth or falsity of `p' : Prop` from an equivalence `p ↔ p'`. -/
def deriveBool (p : Q(Prop)) : MetaM ((b : Bool) × BoolResult p b) 
goal: Lean.MetaM ((b : Bool) × Mathlib.Meta.NormNum.BoolResult p b)

full_name: Mathlib.Meta.NormNum.deriveBoolOfIff
code: /-- Run each registered `norm_num` extension on a typed expression `p : Prop`,
and returning the truth or falsity of `p' : Prop` from an equivalence `p ↔ p'`. -/
def deriveBoolOfIff (p p' : Q(Prop)) (hp : Q($p ↔ $p')) :
    MetaM ((b : Bool) × BoolResult p' b) 
goal: Lean.MetaM ((b : Bool) × Mathlib.Meta.NormNum.BoolResult p' b)

full_name: Mathlib.Meta.NormNum.eval
code: /-- Run each registered `norm_num` extension on an expression,
returning a `Simp.Result`. -/
def eval (e : Expr) (post := false) : MetaM Simp.Result 
goal: Lean.MetaM Lean.Meta.Simp.Result

full_name: Mathlib.Meta.NormNum.NormNums.eraseCore
code: /-- Erases a name marked `norm_num` by adding it to the state's `erased` field and
  removing it from the state's list of `Entry`s. -/
def NormNums.eraseCore (d : NormNums) (declName : Name) : NormNums 
goal: Mathlib.Meta.NormNum.NormNums

full_name: Mathlib.Meta.NormNum.NormNums.erase
code: /--
  Erase a name marked as a `norm_num` attribute.

  Check that it does in fact have the `norm_num` attribute by making sure it names a `NormNumExt`
  found somewhere in the state's tree, and is not erased.
-/
def NormNums.erase {m : Type → Type} [Monad m] [MonadError m] (d : NormNums) (declName : Name) :
    m NormNums 
goal: m Mathlib.Meta.NormNum.NormNums

full_name: Mathlib.Meta.NormNum.initFn._@.Mathlib.Tactic.NormNum.Core._hyg.2343
code: initialize registerBuiltinAttribute {
  name := `norm_num
  descr := "adds a norm_num extension"
  applicationTime := .afterCompilation
  add := fun declName stx kind ↦ match stx with
    | `(attr| norm_num $es,*) => do
      let env ← getEnv
      unless (env.getModuleIdxFor? declName).isNone do
        throwError "invalid attribute 'norm_num', declaration is in an imported module"
      if (IR.getSorryDep env declName).isSome then return -- ignore in progress definitions
      let ext ← mkNormNumExt declName
      let keys ← MetaM.run' <| es.getElems.mapM fun stx ↦ do
        let e ← TermElabM.run' <| withSaveInfoContext <| withAutoBoundImplicit <|
          withReader ({ · with ignoreTCFailures := true }) do
            let e ← elabTerm stx none
            let (_, _, e) ← lambdaMetaTelescope (← mkLambdaFVars (← getLCtx).getFVars e)
            return e
        DiscrTree.mkPath e discrTreeConfig
      normNumExt.add ((keys, declName), ext) kind
    | _ => throwUnsupportedSyntax
  erase := fun declName => do
    let s := normNumExt.getState (← getEnv)
    let s ← s.erase declName
    modifyEnv fun env => normNumExt.modifyState env fun _ => s
}
goal: IO Unit

full_name: Mathlib.Meta.NormNum.tryNormNum
code: /-- A simp plugin which calls `NormNum.eval`. -/
def tryNormNum (post := false) (e : Expr) : SimpM Simp.Step 
goal: Lean.Meta.SimpM Lean.Meta.Simp.Step

full_name: Mathlib.Meta.NormNum.normNumAt
code: /--
The core of `norm_num` as a tactic in `MetaM`.

* `g`: The goal to simplify
* `ctx`: The simp context, constructed by `mkSimpContext` and
  containing any additional simp rules we want to use
* `fvarIdsToSimp`: The selected set of hypotheses used in the location argument
* `simplifyTarget`: true if the target is selected in the location argument
* `useSimp`: true if we used `norm_num` instead of `norm_num1`
-/
def normNumAt (g : MVarId) (ctx : Simp.Context) (fvarIdsToSimp : Array FVarId)
    (simplifyTarget := true) (useSimp := true) :
    MetaM (Option (Array FVarId × MVarId)) 
goal: Lean.MetaM (Option (Array Lean.FVarId × Lean.MVarId))

full_name: Mathlib.Meta.NormNum.getSimpContext
code: /-- Constructs a simp context from the simp argument syntax. -/
def getSimpContext (cfg args : Syntax) (simpOnly := false) : TacticM Simp.Context 
goal: Lean.Elab.Tactic.TacticM Lean.Meta.Simp.Context

full_name: Mathlib.Meta.NormNum.elabNormNum
code: /--
Elaborates a call to `norm_num only? [args]` or `norm_num1`.
* `args`: the `(simpArgs)?` syntax for simp arguments
* `loc`: the `(location)?` syntax for the optional location argument
* `simpOnly`: true if `only` was used in `norm_num`
* `useSimp`: false if `norm_num1` was used, in which case only the structural parts
  of `simp` will be used, not any of the post-processing that `simp only` does without lemmas
-/
-- FIXME: had to inline a bunch of stuff from `mkSimpContext` and `simpLocation` here
def elabNormNum (cfg args loc : Syntax) (simpOnly := false) (useSimp := true) : TacticM Unit 
goal: Lean.Elab.Tactic.TacticM Unit

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_NormNum_Core___elabRules_Mathlib_Tactic_normNum_1
code: /--
Normalize numerical expressions. Supports the operations `+` `-` `*` `/` `⁻¹` `^` and `%`
over numerical types such as `ℕ`, `ℤ`, `ℚ`, `ℝ`, `ℂ` and some general algebraic types,
and can prove goals of the form `A = B`, `A ≠ B`, `A < B` and `A ≤ B`, where `A` and `B` are
numerical expressions. It also has a relatively simple primality prover.
-/
elab (name := normNum)
    "norm_num" cfg:(config ?) only:&" only"? args:(simpArgs ?) loc:(location ?) : tactic =>
  elabNormNum cfg args loc (simpOnly := only.isSome) (useSimp := true)
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.normNum
code: /--
Normalize numerical expressions. Supports the operations `+` `-` `*` `/` `⁻¹` `^` and `%`
over numerical types such as `ℕ`, `ℤ`, `ℚ`, `ℝ`, `ℂ` and some general algebraic types,
and can prove goals of the form `A = B`, `A ≠ B`, `A < B` and `A ≤ B`, where `A` and `B` are
numerical expressions. It also has a relatively simple primality prover.
-/
elab (name := normNum)
    "norm_num" cfg:(config ?) only:&" only"? args:(simpArgs ?) loc:(location ?) : tactic =>
  elabNormNum cfg args loc (simpOnly := only.isSome) (useSimp := true)
goal: Lean.ParserDescr

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_NormNum_Core___elabRules_Mathlib_Tactic_normNum1_1
code: /-- Basic version of `norm_num` that does not call `simp`. -/
elab (name := normNum1) "norm_num1" loc:(location ?) : tactic =>
  elabNormNum mkNullNode mkNullNode loc (simpOnly := true) (useSimp := false)
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.normNum1
code: /-- Basic version of `norm_num` that does not call `simp`. -/
elab (name := normNum1) "norm_num1" loc:(location ?) : tactic =>
  elabNormNum mkNullNode mkNullNode loc (simpOnly := true) (useSimp := false)
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.normNum1Conv
code: @[inherit_doc normNum1] syntax (name := normNum1Conv) "norm_num1" : conv
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.elabNormNum1Conv
code: /-- Elaborator for `norm_num1` conv tactic. -/
@[tactic normNum1Conv] def elabNormNum1Conv : Tactic 
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.normNumConv
code: @[inherit_doc normNum] syntax (name := normNumConv)
    "norm_num" (config)? &" only"? (simpArgs)? : conv
goal: Lean.ParserDescr

full_name: Mathlib.Tactic.elabNormNumConv
code: /-- Elaborator for `norm_num` conv tactic. -/
@[tactic normNumConv] def elabNormNumConv : Tactic 
goal: Lean.Elab.Tactic.Tactic

full_name: Mathlib.Tactic.normNumCmd
code: macro (name := normNumCmd) "#norm_num" cfg:(config)? o:(&" only")?
    args:(Parser.Tactic.simpArgs)? " :"? ppSpace e:term : command =>
  `(command| #conv norm_num $(cfg)? $[only%$o]? $(args)? => $e)
goal: Lean.ParserDescr

full_name: Mathlib.Tactic._aux_Mathlib_Tactic_NormNum_Core___macroRules_Mathlib_Tactic_normNumCmd_1
code: macro (name := normNumCmd) "#norm_num" cfg:(config)? o:(&" only")?
    args:(Parser.Tactic.simpArgs)? " :"? ppSpace e:term : command =>
  `(command| #conv norm_num $(cfg)? $[only%$o]? $(args)? => $e)
goal: Lean.Macro