Zulip Chat Archive
Stream: lean4
Topic: getting `aesop` to use cases with custom cases eliminators
Robin Carlier (Mar 25 2025 at 07:29):
Consider this #mwe (which is probably not as minimal as it could be)
import Mathlib.Logic.Unique
import Aesop
inductive CustomType
  | left
  | right
attribute [local aesop safe cases] CustomType -- works
def CustomHom : CustomType → CustomType → Type
  | .left, .left => PUnit
  | .right, .left => PEmpty
  | .left, .right => PUnit
  | .right, .right => PUnit
instance : Unique (CustomHom .left .left) := inferInstanceAs (Unique PUnit)
instance : Unique (CustomHom .left .right) := inferInstanceAs (Unique PUnit)
instance : Unique (CustomHom .right .right) := inferInstanceAs (Unique PUnit)
@[elab_as_elim, cases_eliminator, induction_eliminator]
def customHomInduction
    {P : {x y : CustomType} → (CustomHom x y) → Sort*}
    (left : P (default : CustomHom .left .left))
    (right : P (default : CustomHom .right .right))
    (left_right : P (default : CustomHom .left .right))
    {x y : CustomType} (f : CustomHom x y) : P f :=
  match x, y, f with
  | .left, .left, _ => left
  | .right, .right, _ => right
  | .left, .right, _ => left_right
attribute [local aesop safe cases] CustomHom -- fails
Are there some aesop magic words to get aesop to call cases on hypotheses of the form f : CustomHom x y?
Jannis Limperg (Mar 26 2025 at 15:48):
This works:
import Mathlib.Logic.Unique
import Aesop
inductive CustomType
  | left
  | right
attribute [local aesop safe cases] CustomType -- works
def CustomHom : CustomType → CustomType → Type
  | .left, .left => PUnit
  | .right, .left => PEmpty
  | .left, .right => PUnit
  | .right, .right => PUnit
instance : Unique (CustomHom .left .left) := inferInstanceAs (Unique PUnit)
instance : Unique (CustomHom .left .right) := inferInstanceAs (Unique PUnit)
instance : Unique (CustomHom .right .right) := inferInstanceAs (Unique PUnit)
@[elab_as_elim, cases_eliminator, induction_eliminator]
def customHomInduction
    {P : {x y : CustomType} → (CustomHom x y) → Sort*}
    (left : P (default : CustomHom .left .left))
    (right : P (default : CustomHom .right .right))
    (left_right : P (default : CustomHom .left .right))
    {x y : CustomType} (f : CustomHom x y) : P f := by
  aesop (add norm unfold CustomHom)
The issue is that Aesop needs to be told to reduce CustomHom .right .left to PEmpty; after that it does cases on PEmpty via a built-in rule.
Jannis Limperg (Mar 26 2025 at 15:50):
Another way:
import Mathlib.Logic.Unique
import Aesop
inductive CustomType
  | left
  | right
attribute [local aesop safe cases] CustomType -- works
def CustomHom : CustomType → CustomType → Type
  | .left, .left => PUnit
  | .right, .left => PEmpty
  | .left, .right => PUnit
  | .right, .right => PUnit
instance : Unique (CustomHom .left .left) := inferInstanceAs (Unique PUnit)
instance : Unique (CustomHom .left .right) := inferInstanceAs (Unique PUnit)
instance : Unique (CustomHom .right .right) := inferInstanceAs (Unique PUnit)
@[aesop norm forward]
theorem customHom_right_left_false : CustomHom .right .left → False := nofun
@[elab_as_elim, cases_eliminator, induction_eliminator]
def customHomInduction
    {P : {x y : CustomType} → (CustomHom x y) → Sort*}
    (left : P (default : CustomHom .left .left))
    (right : P (default : CustomHom .right .right))
    (left_right : P (default : CustomHom .left .right))
    {x y : CustomType} (f : CustomHom x y) : P f := by
  aesop
Robin Carlier (Mar 26 2025 at 16:19):
I am a bit confused, I was not asking how I could get aesop to prove customHomInduction, but rather how to tell aesop to use customCaseInduction as a cases rule in other goals for other lemmas once it’s proven.  Are you telling me that this is in fact what aesop norm forward or aesop norm unfold achieves?
Jannis Limperg (Mar 26 2025 at 16:25):
Ah, I see. Registering custom eliminators as cases rules is currently not supported (unfortunately). But if you use the proposed Aesop rules, they should be equivalent to registering customHomInduction: for any hypothesis f : CustomHom x y, the rules will perform cases on x and y, then close the resulting subgoal for x = right and y = left, leaving you with the three cases that would have been generated by customHomInduction.
The only downside of this approach is that cases will also be run on any hypotheses x : CustomType that don't appear in a CustomHom hyp.
Robin Carlier (Mar 26 2025 at 16:28):
Given that I am fine with attribute [local aesop safe cases] CustomType, I’m okay with aesop callin cases on every x : CustomType in context, thanks!
Last updated: May 02 2025 at 03:31 UTC