(*---------------------------------------------------------------------------*
 * CONDITIONAL EXPRESSIONS AND THEIR NORMALIZATION (Boyer and Moore).        *
 *---------------------------------------------------------------------------*)

app load ["bossLib","QLib"];
open bossLib arithmeticTheory;
infix &&;

(*---------------------------------------------------------------------------*
 * Define the datatype of conditional expressions.                           *
 *---------------------------------------------------------------------------*)

Hol_datatype `cond = A of ind
                   | IF of cond => cond => cond`;


(*---------------------------------------------------------------------------*
 * The definition of the normalization function                              *
 *---------------------------------------------------------------------------*)

val Norm_def = 
 Hol_defn "Norm"
     `(Norm (A i)               = A i)
 /\   (Norm (IF (A x) y z)      = IF (A x) (Norm y) (Norm z)) 
 /\   (Norm (IF (IF u v w) y z) = Norm (IF u (IF v y z) (IF w y z)))`;


(*---------------------------------------------------------------------------*
 *  Termination, via a prim. rec measure function, due to Robert Shostak.    *
 *---------------------------------------------------------------------------*)

val Meas_def = 
 Define
     `(Meas (A i) = 1)
  /\  (Meas (IF x y z) = Meas x + (Meas x * Meas y + Meas x * Meas z))`;


val Meas_POSITIVE = Q.prove
(`!c. 0 < Meas c`, Induct THEN RW_TAC arith_ss [Meas_def]);


val (Norm_eqns,Norm_ind) = 
 Defn.tprove
  (Norm_def,
   WF_REL_TAC Norm_def `measure Meas`
     THEN RW_TAC arith_ss 
           [Meas_def,LEFT_ADD_DISTRIB,RIGHT_ADD_DISTRIB,
            GSYM ADD_ASSOC, GSYM MULT_ASSOC]
     THEN PROVE_TAC [LESS_MULT2, Meas_POSITIVE, 
                     DECIDE `!y m. 0<y ==> m < n+(y+m)`]);


(*---------------------------------------------------------------------------*
 * Another termination proof uses a lexicographic combination of             *
 * relations. This is the version given in the Boyer-Moore book.             *
 *---------------------------------------------------------------------------*)

val Tdepth_def = 
 Define
     `(Tdepth (A i) = 0) /\
      (Tdepth (IF x y z) = Tdepth x + 1)`;

val Weight_def = 
 Define
     `(Weight (A i) = 1) /\
      (Weight (IF x y z) = Weight x * (Weight y + Weight z))`;

val Weight_positive = Q.prove
(`!c. 0 < Weight c`,
 Induct 
    THEN ZAP_TAC (arith_ss && [Weight_def,GSYM ADD_ASSOC, GSYM MULT_ASSOC,
                    LEFT_ADD_DISTRIB,RIGHT_ADD_DISTRIB])
       [LESS_MULT2, DECIDE `!x y z. x < y ==> x < y + z`]);

val (Norm_eqns,Norm_ind) = 
Defn.tprove
 (Norm_def,
  WF_REL_TAC Norm_def `inv_image ($< LEX $<) (\x. (Weight x, Tdepth x))`
     THEN ZAP_TAC (arith_ss && [Weight_def,Tdepth_def,
            LEFT_ADD_DISTRIB,RIGHT_ADD_DISTRIB, 
            GSYM ADD_ASSOC, GSYM MULT_ASSOC, ADD_CLAUSES, MULT_CLAUSES])
           [Weight_positive, DECIDE `!y z. 0 < y ==> z < y+z`, ADD_SYM]);
