Zulip Chat Archive
Stream: Program verification
Topic: Induction over RTC
Andrew (Jul 17 2025 at 13:39):
Hi! I am writing a program logic that defines small-step semantics as follows:
abbrev Configuration := Command × Stack × Trace
inductive small_step : Configuration -> Configuration -> Prop
...
I define a reflexive transitive closure over the small step like this:
inductive rtc (r : α → α → Prop) : α -> α → Prop
| refl (x : α) : rtc r x x
| step (x y z : α) : r x y -> rtc r y z → rtc r x z
def small_step_rtc := rtc small_step
Now, I have a hypothesis of the form:
(skip, σ, τ) ⇝* (skip, σ', τ')
where ⇝* is the small-step reflexive transitive closure. But when I try to perform an induction on this hypothesis, I get:
Invalid target: Index in target's type is not a variable (consider using the `cases` tactic instead)
(skip, σ, τ)
Is there any way to do this induction without this error? I have tried generalizing and rewriting away my triples, but this is an enormous hassle. Given that I will have to do many inductions of this form, it seems insane to me that I will have to use a workaround for a very simple use-case
Malvin Gattinger (Jul 17 2025 at 13:43):
There is docs#Relation.ReflTransGen in mathlib, coming with several useful lemmas and induction principles like docs#Relation.ReflTransGen.head_induction_on that you can use with induction some_rtc_hyp using Relation.ReflTransGen.head_induction_on. Maybe use that or have a look how those are proven? (And in my own project here in Pdl.Star are some more lemmas about it.)
An #mwe in one code block that workds in the live-lean browser thingy would be good to help you better.
Andrew (Jul 17 2025 at 13:50):
Unfortunately the ReflTransGen is in the wrong order (I'm looking for R a b -> RTC R b c -> R a c whereas ReflTransGen does RTC R a b -> R b c -> RTC R a c)
Andrew (Jul 17 2025 at 13:51):
I'm currently loking over how to use head_induction_on
Andrew (Jul 17 2025 at 13:53):
This is the #mwe if you'd care to have a look. It seems to be a known limitation of lean that you can't do induction on tuples https://live.lean-lang.org/#codez=JYWwDg9gTgLgBAWQIYwBYBtgCMB0AZCAc2AGMcAlAU3RWAgDsAoRgE0oDM4BnAVxDgBccAHIo4AdZFiAtAD4pMRgB84ACiQAaOFgCUcALzykcANTbm6SiBDH2ECIO581m7Xv1P+qrFqR65cABiSOhclIIeWACejHBwwPQwUBBccKix8fQsPCQwdPRpcISU9JRQIcAAXgmEcMZYGVzQUFFAA
Malvin Gattinger (Jul 17 2025 at 13:56):
What would the induction proof here be in English? Why do you want induction in the first place? The sum type here is not inductive, i.e. it does not have values that contain values of the sum type itself, right?
Aaron Liu (Jul 17 2025 at 13:56):
Andrew said:
Unfortunately the ReflTransGen is in the wrong order (I'm looking for R a b -> RTC R b c -> R a c whereas ReflTransGen does RTC R a b -> R b c -> RTC R a c)
that's a theorem
Aaron Liu (Jul 17 2025 at 13:57):
Andrew said:
It seems to be a known limitation of lean that you can't do induction on tuples
this feels false
Andrew (Jul 17 2025 at 13:57):
Malvin Gattinger said:
What would the induction proof here be in English? Why do you want induction in the first place? The
sumtype here is not inductive, i.e. it does not have values that contain values of thesumtype itself, right?
This example doesn't have anything to do with what I'm actually doing, it just surfaces the error I'm running into
Malvin Gattinger (Jul 17 2025 at 13:58):
Can you give us a more realistic example then? The lemma here seems false because sum (1,2) = sum (2,1) right? And have you tried using cases instead?
Andrew (Jul 17 2025 at 13:59):
I can't use cases, because in this example I need the inductive hypothesis
Andrew (Jul 17 2025 at 13:59):
It genuinely doesn't matter what I'm doing, i just need to be able to do an induction in which the hypothesis contains a tuple
Aaron Liu (Jul 17 2025 at 13:59):
I will need more context
Andrew (Jul 17 2025 at 14:00):
If you see the error in the #mwe, I'm just trying to get the induction tactic to not fail
Aaron Liu (Jul 17 2025 at 14:00):
induction on tuples is complicated and it depends on what kind of induction hypotheses you need and whether you are inducting on Props or Types
Aaron Liu (Jul 17 2025 at 14:01):
Andrew said:
If you see the error in the #mwe, I'm just trying to get the induction tactic to not fail
not sure what you want to accomplish here
Andrew (Jul 17 2025 at 14:01):
So in my example what I have is a triple:
hstep : (skip, σ, τ) ⇝* (skip, σ', τ')
Aaron Liu (Jul 17 2025 at 14:01):
your goal is false and there aren't any inductive hypotheses
Andrew (Jul 17 2025 at 14:01):
Here skip is a constant and sigma and tau are variables
Aaron Liu (Jul 17 2025 at 14:01):
oh I see
Andrew (Jul 17 2025 at 14:02):
What I want is to just get induction hstep to go through
Aaron Liu (Jul 17 2025 at 14:03):
I would do generalize ha : (skip, σ, τ) = a, hb : (skip, σ', τ') = b at hstep followed by induction hstep generalizing ... for a sufficient amount of generalizing
Aaron Liu (Jul 17 2025 at 14:03):
it really depends on what you want the induction hypothesis to look like
Andrew (Jul 17 2025 at 14:03):
Yeah so that was my original question
Andrew (Jul 17 2025 at 14:04):
What I currently have is this:
generalize hπ : (skip, σ, τ) = π
generalize hπ' : (skip, σ', τ') = π'
rw [hπ, hπ'] at hstep
induction hstep
Malvin Gattinger (Jul 17 2025 at 14:04):
import Mathlib.Logic.Relation
def Command : Type := sorry
def Stack : Type := sorry
def Trace : Type := sorry
abbrev Configuration := Command × Stack × Trace
def small_step : Configuration -> Configuration -> Prop := sorry
def big_step := Relation.ReflTransGen small_step
def isNice : Configuration → Prop := sorry
theorem something (h : big_step a b ) : isNice b := by
induction h
case refl =>
sorry
case tail IH =>
sorry
theorem something_head (h : big_step a b ) : isNice b := by
induction h using Relation.ReflTransGen.head_induction_on
case refl =>
sorry
case head IH =>
sorry
Andrew (Jul 17 2025 at 14:04):
I'm trying to figure out if there's either an idiomatic or less repetitive way of doing this
Aaron Liu (Jul 17 2025 at 14:05):
yeah I have nothing
Andrew (Jul 17 2025 at 14:08):
Thanks for the support both of you
Andrew (Jul 17 2025 at 14:08):
Malvin Gattinger said:
import Mathlib.Logic.Relation def Command : Type := sorry def Stack : Type := sorry def Trace : Type := sorry abbrev Configuration := Command × Stack × Trace def small_step : Configuration -> Configuration -> Prop := sorry def big_step := Relation.ReflTransGen small_step def isNice : Configuration → Prop := sorry theorem something (h : big_step a b ) : isNice b := by induction h case refl => sorry case tail IH => sorry theorem something_head (h : big_step a b ) : isNice b := by induction h using Relation.ReflTransGen.head_induction_on case refl => sorry case head IH => sorry
Im going to see if I can refactor my proof to make this work
Andrew (Jul 17 2025 at 14:09):
Aaron Liu said:
Andrew said:
Unfortunately the ReflTransGen is in the wrong order (I'm looking for R a b -> RTC R b c -> R a c whereas ReflTransGen does RTC R a b -> R b c -> RTC R a c)
that's a theorem
Can you point me at any way to make the RTC work in the order I want? I'd like to use the Mathlib one if at all possible
Aaron Liu (Jul 17 2025 at 14:10):
docs#Relation.ReflTransGen.head is the theorem
Malvin Gattinger (Jul 17 2025 at 14:11):
In my example above please place the cursor after case head IH =>and look at the info view :)
Aaron Liu (Jul 17 2025 at 14:11):
there's also docs#Relation.ReflTransGen.trans and docs#Relation.ReflTransGen.single
Aaron Liu (Jul 17 2025 at 14:11):
there's a lot of theorems
Andrew (Jul 17 2025 at 14:11):
Thanks
Andrew (Jul 17 2025 at 14:11):
That's a huge help
Aaron Liu (Jul 17 2025 at 14:11):
you're probably better off looking them up on your own rather than having me list them off
Last updated: Dec 20 2025 at 21:32 UTC