Some lemmas on chain generation

Introduction

This file contains some important lemmas used in the generation module. They tell us how to compose abstract machine code to build code for Call_M, Call_C and Call_K calls (see the module spec )

We prove 7 lemmas, which all have the same form:

(...)(gencode call1)-> 
    (gencode call2)-> ...
    (gencode call).
Proof.
Realizer [...][c1,c2,...:Code]c.
...
Qed.
where call1,... are terms of type Call, and c is a Fw-term of type Code.

Lemmas for Call_M

M3:(gencode (Call_M three))

This lemma states that we can construct a code for (Call_M three): it is a constructive proof (realized by the code (seq PUSH (seq SQR (seq MUL End))))

M2q:(q:nat)(gencode (Call_M (two_power q)))

The code for (Call_M (two_power p)) is obtained by a sequence of p SQRs. So the proof begins with:
Realizer [p:nat]<Code>Match p with End
                                   ([_,c:?](seq SQR  c))
                 end.

 
C2M:(p,q:nat)(gencode (Call_C p q ))->
             (gencode  (Call_M p)).

The specification for (Call_M p q) is stronger than the specification of (Call_M p). So this lemma is realized by identity on Code:
 Realizer [p,q:nat][c:Code]c.

Lemmas for Call_C

MMC:(p,q:nat)(gencode (Call_M p))->
             (gencode (Call_M q))->
             (gencode (Call_C (mult q p) p)).

If you know how to compute a p-th power [a q-th power], with the code c [resp. c'], then the concatenation of c and c' allows you to compute a pq-th power: (it comes from the relation x^(pq)=((x^p)^q))

Therefore, the proof begins with:

Realizer [p,q:nat][c,c':Code](app c  c').
Program_all.

KMC:(p,q,r:nat)(gencode (Call_K p r))->
               (gencode (Call_M q))->
               (gencode (Call_C (plus (mult q p) r) p)).

For computing x^(qp+r), with the computation of x^p as an intermediate step, it is enough to compute x^p and x^r (with a code cpr), then raise x^p to it's q-th power (with code cq) then multiply it by x^p. So, the constructive proof of KMC is realized by:
Realizer [p,q,r:nat][cpr,cq:Code]
               (app cpr (app cq (seq MUL End))).
...

Lemmas for Call_K

MMK: (p,q:nat)(gencode (Call_M p))->
              (gencode (Call_M q))->
              (gencode (Call_K (mult q p) p)).

In order to compute x^(pq) and x^p, one may first compute x^p (with the code cp), then push x^p on the stack, and compute x^(pq)=(x^p)^q with the code cq:
Realizer [p,q:nat][cp,cq:Code](app cp  (seq PUSH  cq)).

KMK:(p,q,r:nat)
      (gencode (Call_K p r))->
      (gencode (Call_M q))->
      (gencode (Call_K (plus (mult q p) r) p)).

In order to compute x^(pq+r) and x^p first compute x^r and x^p, then push x^p, swap x^p and x^r, then compute (x^p)^q and multiply this last value with x^r:
Realizer [p,q,r:nat][kpr,mq:Code]
  (app kpr (seq PUSH (seq SWAP(app mq (seq MUL End))))).

For the beginner ...

As said above, the proofs of all these lemmas share the same structure: We use Realizer andProgram, and have to solve some logical goals. These goals are solved using some properties of the monoid ; the lemma Exec_app of the module machine is used to prove the correction of code obtained by appending.

Please notice the repeated use of Inversion_clear s, where s is an hypothesis of the form (Spec <some_call> c0), where <some_call> is a term of type Call and c0 a variable of type Code.

For instance, in the proof of KMC, we have the context:

  p : nat
  q : nat
  c : (gencode (Call_M p))
  c0 : Code
  s : (Spec (Call_M p) c0)
  c' : (gencode (Call_M q))
  c'0 : Code
  s0 : (Spec (Call_M q) c'0)
  a : M
  s1 : Stack
  ============================
   (Exec c'0 (Exec c0 (config a s1)))=
   (config (power a (mult q p)) s1)
the command "Inversion_clear s." adds to the context the hypothesis
H: (a:M)(s:Stack)(Exec c0 (config a s))=
                 (config (power a p) s)
which reflects the intended semantics of (Call_M p) (see the module spec ), and is used as "Rewrite H.";
For seeing the source, please click here .

Play it in Caml!

As usual load and open the file "demo.ml";
load "Demo.ml";;
#open "Demo";;
The lemmas M3,M2q, MMC, ... have their ml translations:
#M3;;
- : Code = seq (PUSH, seq (SQR, seq (MUL, End)))
#M2q 6;;
- : Code =
 seq (SQR,seq(SQR,seq(SQR,seq(SQR,seq(SQR,seq(SQR,End))))))

#KMC 10 8 7 (code_gen (dicho log2_impl) 
                      (Call_K(10, 7)))
            (code_gen (dicho log2_impl) (Call_M 8))
  =
 (code_gen (dicho log2_impl) (Call_M 87));;
- : builtin__bool = builtin__true

Remark

If we look at the Caml source for, say, KMC:
let KMC p q r cpr cq =
  app cpr (app cq (seq(MUL,End)));;
we notice that the integer parameters p, q, and r are useless in the body of the definition. This is perfectly normal: p, q, and r are of type nat(int) which is of type Set, and are not removed by extraction, but they are used only for logical purpose, and their use in removed by the extraction algorithm.