1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
|
(***********************************************************************)
(* v * The Coq Proof Assistant / The Coq Development Team *)
(* <O___,, * INRIA-Rocquencourt & LRI-CNRS-Orsay *)
(* \VV/ *************************************************************)
(* // * This file is distributed under the terms of the *)
(* * GNU Lesser General Public License Version 2.1 *)
(***********************************************************************)
(* Certification of Imperative Programs / Jean-Christophe Fillitre *)
(*i $Id: exp.v,v 1.3 2001/04/11 07:56:19 filliatr Exp $ i*)
(* Efficient computation of X^n using
*
* X^(2n) = (X^n) ^ 2
* X^(2n+1) = X . (X^n) ^ 2
*
* Proofs of both fonctional and imperative programs.
*)
Require Even.
Require Div2.
Require Correctness.
Require ArithRing.
Require ZArithRing.
(* The specification uses the traditional definition of X^n *)
Fixpoint power [x,n:nat] : nat :=
Cases n of
O => (S O)
| (S n') => (mult x (power x n'))
end.
Definition square := [n:nat](mult n n).
(* Three lemmas are necessary to establish the forthcoming proof obligations *)
(* n = 2*(n/2) => (x^(n/2))^2 = x^n *)
Lemma exp_div2_0 : (x,n:nat)
n=(double (div2 n))
-> (square (power x (div2 n)))=(power x n).
Proof.
Unfold square.
Intros x n. Pattern n. Apply ind_0_1_SS.
Auto.
Intro. (Absurd (1)=(double (0)); Auto).
Intros. Simpl.
Cut n0=(double (div2 n0)).
Intro. Rewrite <- (H H1).
Ring.
Simpl in H0.
Unfold double in H0.
Simpl in H0.
Rewrite <- (plus_n_Sm (div2 n0) (div2 n0)) in H0.
(Injection H0; Auto).
Save.
(* n = 2*(n/2)+1 => x*(x^(n/2))^2 = x^n *)
Lemma exp_div2_1 : (x,n:nat)
n=(S (double (div2 n)))
-> (mult x (square (power x (div2 n))))=(power x n).
Proof.
Unfold square.
Intros x n. Pattern n. Apply ind_0_1_SS.
Intro. (Absurd (0)=(S (double (0))); Auto).
Auto.
Intros. Simpl.
Cut n0=(S (double (div2 n0))).
Intro. Rewrite <- (H H1).
Ring.
Simpl in H0.
Unfold double in H0.
Simpl in H0.
Rewrite <- (plus_n_Sm (div2 n0) (div2 n0)) in H0.
(Injection H0; Auto).
Save.
(* x^(2*n) = (x^2)^n *)
Lemma power_2n : (x,n:nat)(power x (double n))=(power (square x) n).
Proof.
Unfold double. Unfold square.
Induction n.
Auto.
Intros.
Simpl.
Rewrite <- H.
Rewrite <- (plus_n_Sm n0 n0).
Simpl.
Auto with arith.
Save.
Hints Resolve exp_div2_0 exp_div2_1.
(* Functional version.
*
* Here we give the functional program as an incomplete CIC term,
* using the tactic Refine.
*
* On this example, it really behaves as the tactic Program.
*)
(*
Lemma f_exp : (x,n:nat) { y:nat | y=(power x n) }.
Proof.
Refine [x:nat]
(well_founded_induction nat lt lt_wf
[n:nat]{y:nat | y=(power x n) }
[n:nat]
[f:(p:nat)(lt p n)->{y:nat | y=(power x p) }]
Cases (zerop n) of
(left _) => (exist ? ? (S O) ?)
| (right _) =>
let (y,H) = (f (div2 n) ?) in
Cases (even_odd_dec n) of
(left _) => (exist ? ? (mult y y) ?)
| (right _) => (exist ? ? (mult x (mult y y)) ?)
end
end).
Proof.
Rewrite a. Auto.
Exact (lt_div2 n a).
Change (square y)=(power x n). Rewrite H. Auto with arith.
Change (mult x (square y))=(power x n). Rewrite H. Auto with arith.
Save.
*)
(* Imperative version. *)
Definition even_odd_bool := [x:nat](bool_of_sumbool ? ? (even_odd_dec x)).
Correctness i_exp
fun (x:nat)(n:nat) ->
let y = ref (S O) in
let m = ref x in
let e = ref n in
begin
while (notzerop_bool !e) do
{ invariant (power x n)=(mult y (power m e)) as Inv
variant e for lt }
(if not (even_odd_bool !e) then y := (mult !y !m))
{ (power x n) = (mult y (power m (double (div2 e)))) as Q };
m := (square !m);
e := (div2 !e)
done;
!y
end
{ result=(power x n) }
.
Proof.
Rewrite (odd_double e0 Test1) in Inv. Rewrite Inv. Simpl. Auto with arith.
Rewrite (even_double e0 Test1) in Inv. Rewrite Inv. Reflexivity.
Split.
Exact (lt_div2 e0 Test2).
Rewrite Q. Unfold double. Unfold square.
Simpl.
Change (mult y1 (power m0 (double (div2 e0))))
= (mult y1 (power (square m0) (div2 e0))).
Rewrite (power_2n m0 (div2 e0)). Reflexivity.
Auto with arith.
Decompose [and] Inv.
Rewrite H. Rewrite H0.
Auto with arith.
Save.
(* Recursive version. *)
Correctness r_exp
let rec exp (x:nat) (n:nat) : nat { variant n for lt} =
(if (zerop_bool n) then
(S O)
else
let y = (exp x (div2 n)) in
if (even_odd_bool n) then
(mult y y)
else
(mult x (mult y y))
) { result=(power x n) }
.
Proof.
Rewrite Test2. Auto.
Exact (lt_div2 n0 Test2).
Change (square y)=(power x0 n0). Rewrite Post7. Auto with arith.
Change (mult x0 (square y))=(power x0 n0). Rewrite Post7. Auto with arith.
Save.
|