Search code examples
isabelleinduction

How do I write a custom induction rule over a parameterized inductive set?


I'm trying to write a custom induction rule for an inductive set. Unfortunately, when I try to apply it with induction rule: my_induct_rule, I get an extra, impossible to prove case. I have the following:

inductive iterate :: "('a ⇒ 'a ⇒ bool) ⇒ 'a ⇒ 'a ⇒ bool" for f where
  iter_refl [simp]: "iterate f a a"
| iter_step [elim]: "f a b ⟹ iterate f b c ⟹ iterate f a c"

theorem my_iterate_induct: "iterate f x y ⟹ (⋀a. P a a) ⟹ 
    (⋀a b c. f a b ⟹ iterate f b c ⟹ P b c ⟹ P a c) ⟹ P x y"
  by (induction x y rule: iterate.induct) simp_all

lemma iter_step_backwards: "iterate f a b ⟹ f b c ⟹ iterate f a c"
  proof (induction a b rule: my_iterate_induct)
    ...
  qed

Obviously the custom induction rule doesn't give me any new power (my real use case is more complicated) but that's kinda the point. my_iterate_induct is exactly the same as the autogenerated iterate.induct rule, as far as I can tell, but inside the proof block I have the following goals:

goal (3 subgoals):
 1. iterate ?f a b
 2. ⋀a. iterate f a a ⟹ f a c ⟹ iterate f a c
 3. ⋀a b ca. ?f a b ⟹ iterate ?f b ca ⟹ 
      (iterate f b ca ⟹ f ca c ⟹ iterate f b c) ⟹ iterate f a ca ⟹ 
        f ca c ⟹ iterate f a c

Goal 1 seems to rise from some failure to unify ?f with the actual argument f, but if I ignore the fact that the f is fixed and try induction f a b rule: my_iterate_induct I just get Failed to apply proof method, as expected. How do I get the nice behaviour that the regular iterate.induct provides?


Solution

  • You need to declare your custom induction rule as ‘consuming’ one premise using the consumes attribute (see the Isabelle/Isar reference manual, §6.5.1):

    theorem my_iterate_induct [consumes 1]: "iterate f x y ⟹ (⋀a. P a a) ⟹ 
       (⋀a b c. f a b ⟹ iterate f b c ⟹ P b c ⟹ P a c) ⟹ P x y"
      by (induction x y rule: iterate.induct) simp_all