Quantcast
Channel: How to do theorems that require mutual recursion? - Stack Overflow
Viewing all articles
Browse latest Browse all 2

Answer by Bubbler for How to do theorems that require mutual recursion?

$
0
0

As I commented, I don't know a general way to handle mutually recursive theorems, but (from my shallow experience) I didn't have any need to have a set of mutually recursive theorems unless they involve mutually recursive data types or functions (in which case, I suggest Equations plugin).

This answer focuses on the specific problem.


The problem is very close to the last exercise of Induction Exercises, except that the program halts when the Plus instruction is given too few arguments (which makes the problem slightly harder).

We start with the definitions by @larsr:

Require Import Coq.Lists.List.Import ListNotations.Inductive Sinstr : Set := SPush (_:nat) | SPlus.Inductive Aexp : Set := ANum (_:nat) | APlus (_ _:Aexp).Fixpoint sexec (p:list Sinstr) (s:list nat) : list nat :=  match (p, s) with  | ([], stack) => stack  | ((SPush x)::prog, stack) => sexec prog (x::stack)  | (Splus::prog, x1::x2::stack)  =>  sexec prog (x1+x2::stack)  | (_, stack) => stack  end.Fixpoint aeval (a:Aexp) : nat :=  match a with  | ANum n => n  | APlus a1 a2 => aeval a2 + aeval a1  end.Fixpoint compile (a:Aexp) : list Sinstr :=  match a with  | ANum n => [SPush n]  | APlus a1 a2 => compile a1 ++ compile a2 ++ [SPlus]   end.

First, we try proof by induction directly:

Theorem compile_correct_try e : sexec (compile e) [] = [aeval e].Proof.  induction e; intros; auto. (* base case is easy *)  simpl.e1, e2 : AexpIHe1 : sexec (compile e1) [] = [aeval e1]IHe2 : sexec (compile e2) [] = [aeval e2]____________________________________________sexec (compile e1 ++ compile e2 ++ [SPlus]) [] = [aeval e2 + aeval e1]

We're stuck at this point. We can make some observations though:

  • We need a lemma that involves concatenation of two programs (obviously).
  • We also need a lemma that applies to any initial stack (since compile e2 will run on the stack [aeval e1], not []).

So we try writing a general lemma:

Lemma prg_concat :  forall p1 p2 stack, sexec (p1 ++ p2) stack = sexec p2 (sexec p1 stack).

But this is simply wrong because p2 should not run if p1 was aborted. Then we should ensure that p1 does not abort. One might want to define "runs to completion" prop, but we have an obvious special case that works: compile e. And it fits perfectly to our inductive case, because the left operands to ++ are of the form compile _:

sexec (compile e1 ++ compile e2 ++ [SPlus]) stack->sexec (compile e2 ++ [SPlus]) (sexec (compile e1) stack)->sexec [SPlus] (sexec (compile e2) (sexec (compile e1) stack))

The corresponding statement is:

Lemma compile_concat :  forall e p s, sexec (compile e ++ p) s = sexec p (sexec (compile e) s).

But this is still not enough, because there is no guarantee that the final SPlus will succeed. So we incorporate the main goal sexec (compile e) = [aeval e] into the lemma, i.e. instead of sexec (compile e) s, we write aeval e :: s. Now we can guarantee that there will be at least two elements on the stack when we arrive at the final SPlus.

So here comes larsr's lemma:

Lemma compile_ok (e:Aexp):   forall p s, sexec (compile e ++ p) s = sexec p (aeval e::s).Proof.  induction e.  reflexivity.  intros; simpl;    rewrite <-? app_assoc, IHe1, IHe2; reflexivity.Qed.

Also, here is a documentation of rewrite <-? expr, at the end of section rewrite:

Orientation -> or <- can be inserted before each term to rewrite.

In all forms of rewrite described above, a term to rewrite can be immediately prefixed by one of the following modifiers:

  • ?: the tactic rewrite ?term performs the rewrite of term as many times as possible (perhaps zero time). This form never fails.

So rewrite <-? app_assoc, IHe1, IHe2. means to repeat (reverse) rewriting by app_assoc, and then (forward) rewrite by IHe1 and IHe2 once each.


Viewing all articles
Browse latest Browse all 2

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>