Zulip Chat Archive

Stream: lean4

Topic: Custom pre/post methods in simp


Tomas Skrivan (May 16 2022 at 20:32):

I would like to have the following simp theorem but it should be applied only when the lhs has the let binding:

theorem D_let (g : α  β) (f : α  β  γ)
  : D (λ x =>
         let tmp := g x
         f x tmp)
    = λ x dx =>
         let tmp  := g x
         let dtmp := D g x dx
         D (f x) tmp dtmp + D f x dx tmp

The simplifier ignores the let binding. The lhs could be also written as D (λ x => f x (g x)), it makes no difference. (Recently, I had a question related to this, but I was looking at it from the incorrect angle)

Internally, simplifier has pre and post methods of type Expr -> SimpM Step that are applied to each subterm before or after simp lemmas are applied. I can achieve what I need with a custom pre method. However, currently there is no mechanism how to define it.

I have modifed Lean source code to do that, my lean4 fork. Now, simpLocation has two additional arguments (pres posts : Array (Expr → Simp.SimpM Simp.Step) := #[]) and you can define your own simp tactic with custom pre and post methods:

import Lean.Meta
import Lean.Elab

open Lean Meta Simp

def myPre (e : Expr) : SimpM Step :=
  dbg_trace s!"Running pre  on {e}"
  pure (Step.visit (Result.mk e none))

def myPost (e : Expr) : SimpM Step :=
  dbg_trace s!"Running post on {e}"
  pure (Step.visit (Result.mk e none))

namespace Lean.Elab.Tactic

open Lean.Parser.Tactic

syntax (name := mysimp) "mysimp " (config)? (discharger)? (&"only ")? ("[" (simpStar <|> simpErase <|> simpLemma),* "]")? (location)? : tactic

@[tactic mysimp] def evalMySimp : Tactic := fun stx => do
  let { ctx, fvarIdToLemmaId, dischargeWrapper, pres, posts }  withMainContext <| mkSimpContext stx (eraseLocal := false)
  dbg_trace "Running my simp!"
  dischargeWrapper.with fun discharge? =>
    simpLocation ctx discharge? fvarIdToLemmaId (expandOptLocation stx[5]) #[myPre] #[myPost]

end Lean.Elab.Tactic

@[irreducible] def foo (a b : Nat) := a + b
@[simp] theorem foo_simp (a b : Nat) : foo a b = a + b := by unfold foo; rfl

example (a b : Nat)
  : foo a b = a + b := by mysimp

Outputs:

Running my simp!
Running pre  on Eq.{1} Nat (foo _uniq.823 _uniq.824) (HAdd.hAdd.{0 0 0} Nat Nat Nat (instHAdd.{0} Nat instAddNat) _uniq.823 _uniq.824)
Running pre  on Eq.{1}
Running post on Eq.{1}
Running pre  on foo _uniq.823 _uniq.824
...

I have also attempted to modify default simp such that you can write simp [↓myPre, ↑myPost]. When parsing the tactic, I can get the name myPre : Name and check that a constant with that name has the desired type Expr -> SimpM Step but I'm having hard time converting to the actual value Expr -> SimpM Step. I have tried the command evalConst but that one is unsafe.


Would someone else find this useful? What would be the ideal way to specify custom pre/post methods? Would it make sense to add this change to the core repo?

Leonardo de Moura (May 16 2022 at 21:14):

This is a useful feature, but we don't have cycles to invest in it right now. We are currently trying to focus on bugs and features that we need for porting Mathlib to Lean 4. We do want to provide better support for custom simp extensions in the future. Right now, it is not very convenient as you noticed, and one has to implement their own simp command to be able to provide their own pre and post.

structure Methods where
  pre        : Expr  SimpM Step          := fun e => return Step.visit { expr := e }
  post       : Expr  SimpM Step          := fun e => return Step.done { expr := e }
  discharge? : Expr  SimpM (Option Expr) := fun e => return none

Tomas Skrivan (May 16 2022 at 21:21):

That is exactly what I did, I modified the default Methods inside Lean.Meta.Simp.simp:

  | none   => Simp.main e ctx (methods := Simp.DefaultMethods.methods
                                          |> pres.foldl  (λ m p => m.appendPre p)
                                          |> posts.foldl (λ m p => m.appendPost p))

Yeah I understand that this is not a priority right now, I will find some work around it.

Leonardo de Moura (May 16 2022 at 21:22):

Thanks for your patiencience. We will address this issue in the future.


Last updated: Dec 20 2023 at 11:08 UTC