1(*===========================================================================
2== LIBRARY:     reduce (part II)                                           ==
3==                                                                         ==
4== DESCRIPTION: Conversions to reduce arithmetic constant expressions      ==
5==                                                                         ==
6== AUTHOR:      Michael Norrish                                            ==
7==              University of Cambridge Computer Laboratory                ==
8==              New Museums Site                                           ==
9==              Pembroke Street                                            ==
10==              Cambridge CB2 3QG                                          ==
11==              England.                                                   ==
12==                                                                         ==
13==              mn200@cl.cam.ac.uk                                         ==
14==                                                                         ==
15== DATE:        January 1999                                               ==
16==                                                                         ==
17== NOTE:        The original functionality in this file was provided by    ==
18==              carefully written CONVs.  With the use of proper numerals  ==
19==              (see numeralTheory), this is no longer necessary, and      ==
20==              simple rewriting can be used for most tasks.               ==
21==              It is the (untested) claim that this will be as efficient. ==
22============================================================================*)
23
24structure Arithconv :> Arithconv =
25struct
26
27open HolKernel boolTheory boolLib Parse Rsyntax
28     Num_conv numSyntax arithmeticTheory numeralTheory;
29
30val ambient_grammars = Parse.current_grammars();
31val _ = Parse.temp_set_grammars arithmeticTheory.arithmetic_grammars
32
33val ERR = mk_HOL_ERR "Arithconv"
34fun failwith function = raise (ERR function "")
35
36
37(*---------------------------------------------------------------------------
38    A "conv-al" that takes a conv and makes it fail if the
39    result is not either true, false or a numeral.
40 ---------------------------------------------------------------------------*)
41
42fun TFN_CONV c t =
43 let val result = c t
44     val result_t = rhs (concl result)
45 in
46   if result_t = T orelse result_t = F orelse Literal.is_numeral result_t
47     then result
48     else failwith "TFN_CONV"
49end
50
51
52(*-----------------------------------------------------------------------*)
53(* NEQ_CONV "[x] = [y]" = |- ([x] = [y]) = [x=y -> T | F]                *)
54(*-----------------------------------------------------------------------*)
55
56local
57 val NEQ_RW = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_eq])
58 val REFL_CLAUSE_num = INST_TYPE [alpha |-> num] REFL_CLAUSE
59in
60fun NEQ_CONV tm =
61 case total boolLib.dest_eq tm
62  of NONE => failwith "NEQ_CONV"
63   | SOME (n1,n2) =>
64      if is_numeral n1 andalso is_numeral n2
65      then if n1=n2 then SPEC n1 REFL_CLAUSE_num
66           else with_exn NEQ_RW tm (ERR "NEQ_CONV" "")
67      else failwith "NEQ_CONV"
68end;
69
70(*-----------------------------------------------------------------------*)
71(* LT_CONV "[x] < [y]" = |- ([x] < [y]) = [x<y -> T | F]                 *)
72(*-----------------------------------------------------------------------*)
73
74local val LT_RW = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_lt])
75in
76fun LT_CONV tm =
77  if is_less tm then with_exn LT_RW tm (ERR "LT_CONV" "")
78  else failwith "LT_CONV"
79end;
80
81(*-----------------------------------------------------------------------*)
82(* GT_CONV "[x] > [y]" = |- ([x] > [y]) = [x>y -> T | F]                 *)
83(*-----------------------------------------------------------------------*)
84
85local val GT_RW = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_lt])
86in
87fun GT_CONV tm =
88  if is_greater tm then with_exn GT_RW tm (ERR "GT_CONV" "")
89  else failwith "GT_CONV"
90end;
91
92(*-----------------------------------------------------------------------*)
93(* LE_CONV "[x] <= [y]" = |- ([x]<=> [y]) = [x<=y -> T | F]              *)
94(*-----------------------------------------------------------------------*)
95
96local val LE_RW = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_lte])
97in
98fun LE_CONV tm =
99 if is_leq tm then with_exn LE_RW tm (ERR "LE_CONV" "") else failwith "LE_CONV"
100end;
101
102(*-----------------------------------------------------------------------*)
103(* GE_CONV "[x] >= [y]" = |- ([x] >= [y]) = [x>=y -> T | F]              *)
104(*-----------------------------------------------------------------------*)
105
106local val GE_RW = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_lte])
107in
108fun GE_CONV tm =
109 if is_geq tm then with_exn GE_RW tm (ERR "GE_CONV" "")
110 else failwith "GE_CONV"
111end;
112
113(*-----------------------------------------------------------------------*)
114(* EVEN_CONV "EVEN [x]" = |- EVEN [x] = [ x divisible by 2 -> T | F ]    *)
115(*-----------------------------------------------------------------------*)
116
117local val EC = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_evenodd])
118in
119fun EVEN_CONV tm =
120  if is_even tm then with_exn EC tm (ERR "EVEN_CONV" "")
121  else failwith "EVEN_CONV"
122end
123
124(*-----------------------------------------------------------------------*)
125(* ODD_CONV "ODD [x]" = |- ODD [x] = [ x divisible by 2 -> F | T ]       *)
126(*-----------------------------------------------------------------------*)
127
128local val OC = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_evenodd])
129in
130fun ODD_CONV tm =
131 if is_odd tm then with_exn OC tm (ERR "ODD_CONV" "") else failwith "ODD_CONV"
132end
133
134(*-----------------------------------------------------------------------*)
135(* SUC_CONV "SUC [x]" = |- SUC [x] = [x+1]                               *)
136(*-----------------------------------------------------------------------*)
137
138local val SUC_RW = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_suc])
139in
140fun SUC_CONV tm =
141 if is_suc tm then with_exn SUC_RW tm (ERR "SUC_CONV" "")
142 else failwith "SUC_CONV"
143end;
144
145(*-----------------------------------------------------------------------*)
146(* PRE_CONV "PRE [n]" = |- PRE [n] = [n-1]                               *)
147(*-----------------------------------------------------------------------*)
148
149local
150  val PRE_RW = TFN_CONV (REWRITE_CONV [numeral_distrib, numeral_pre,NORM_0])
151in
152fun PRE_CONV tm =
153 if is_pre tm then with_exn PRE_RW tm (ERR "PRE_CONV" "")
154 else failwith "PRE_CONV"
155end;
156
157(*-----------------------------------------------------------------------*)
158(* SBC_CONV "[x] - [y]" = |- ([x] - [y]) = [x - y]                       *)
159(*-----------------------------------------------------------------------*)
160
161local
162 val SBC_RW =
163   TFN_CONV (REWRITE_CONV
164       [numeral_distrib, numeral_sub,iSUB_THM,
165        iDUB_removal,numeral_pre, numeral_lt])
166in
167fun SBC_CONV tm =
168  if is_minus tm then with_exn SBC_RW tm (ERR "SBC_CONV" "")
169  else failwith "SBC_CONV"
170end;
171
172(*-----------------------------------------------------------------------*)
173(* ADD_CONV "[x] + [y]" = |- [x] + [y] = [x+y]                           *)
174(*-----------------------------------------------------------------------*)
175
176local
177 val ADD_RW =
178   TFN_CONV (REWRITE_CONV
179      [numeral_distrib, numeral_add,numeral_suc, numeral_iisuc])
180in
181fun ADD_CONV tm =
182 if is_plus tm then with_exn ADD_RW tm (ERR "ADD_CONV" "")
183 else failwith "ADD_CONV"
184end;
185
186(*-----------------------------------------------------------------------*)
187(* MUL_CONV "[x] * [y]" = |- [x] * [y] = [x * y]                         *)
188(*-----------------------------------------------------------------------*)
189
190local
191  val MUL_RW =
192    TFN_CONV (REWRITE_CONV
193      [numeral_distrib, numeral_add, numeral_suc,
194       numeral_iisuc, numeral_mult, iDUB_removal, numeral_pre])
195in
196fun MUL_CONV tm =
197  if is_mult tm then with_exn MUL_RW tm (ERR "MUL_CONV" "")
198  else failwith "MUL_CONV"
199end;
200
201(*-----------------------------------------------------------------------*)
202(* EXP_CONV "[x] EXP [y]" = |- [x] EXP [y] = [x ** y]                    *)
203(*-----------------------------------------------------------------------*)
204
205local
206 val RW1 = REWRITE_CONV [numeral_distrib, numeral_exp]
207 val RW2 = REWRITE_CONV [numeral_add, numeral_suc, numeral_iisuc,
208                         numeral_mult, iDUB_removal, numeral_pre, iSQR]
209 val EXP_RW = TFN_CONV (RW1 THENC RW2)
210in
211fun EXP_CONV tm =
212  if is_exp tm then with_exn EXP_RW tm (ERR "EXP_CONV" "")
213  else failwith "EXP_CONV"
214end;
215
216(*-----------------------------------------------------------------------*)
217(* DIV_CONV "[x] DIV [y]" = |- [x] DIV [y] = [x div y]                   *)
218(*-----------------------------------------------------------------------*)
219
220fun provelt x y = EQT_ELIM (LT_CONV (mk_less(mk_numeral x, mk_numeral y)))
221
222val xv = mk_var {Name= "x", Ty=num}
223val yv = mk_var {Name= "y", Ty=num}
224val zv = mk_var {Name= "z", Ty=num}
225val pv = mk_var {Name= "p", Ty=num}
226val qv = mk_var {Name= "q", Ty=num}
227val rv = mk_var {Name= "r", Ty=num};
228
229local val divt =
230    prove((���(q * y = p) ==> (p + r = x) ==> (r < y) ==> (x DIV y = q)���),
231          REPEAT DISCH_TAC THEN
232          MATCH_MP_TAC (arithmeticTheory.DIV_UNIQUE) THEN
233          EXISTS_TAC (���r:num���) THEN ASM_REWRITE_TAC[])
234in
235fun DIV_CONV tm =
236  let open Arbnum
237      val (xn,yn) = dest_div tm
238      val x = dest_numeral xn
239      and y = dest_numeral yn
240      val q = x div y
241      val p = q * y
242      val r = x - p
243      val pn = mk_numeral p
244      and qn = mk_numeral q
245      and rn = mk_numeral r
246      val p1 = MUL_CONV (mk_mult(qn,yn))
247      and p2 = ADD_CONV (mk_plus(pn,rn))
248      and p3 = provelt r y
249      and chain = INST [xv |-> xn, yv |-> yn, pv |-> pn,
250                        qv |-> qn, rv |-> rn] divt
251  in
252     MP (MP (MP chain p1) p2) p3
253  end handle HOL_ERR _ => failwith "DIV_CONV"
254           | Div => raise ERR "DIV_CONV" "attempt to divide by zero"
255end;
256
257(*-----------------------------------------------------------------------*)
258(* MOD_CONV "[x] MOD [y]" = |- [x] MOD [y] = [x mod y]                   *)
259(*-----------------------------------------------------------------------*)
260
261local val modt =
262    prove(���(q * y = p) ==> (p + r = x) ==> (r < y) ==> (x MOD y = r)���,
263          REPEAT DISCH_TAC THEN
264          MATCH_MP_TAC arithmeticTheory.MOD_UNIQUE THEN
265          EXISTS_TAC ���q:num��� THEN ASM_REWRITE_TAC[])
266in
267fun MOD_CONV tm =
268 let open Arbnum
269     val (xn,yn) = dest_mod tm
270     val x = dest_numeral xn
271     and y = dest_numeral yn
272     val q = x div y
273     val p = q * y
274     val r = x - p
275     val pn = mk_numeral p
276     and qn = mk_numeral q
277     and rn = mk_numeral r
278     val p1 = MUL_CONV (mk_mult(qn,yn))
279     and p2 = ADD_CONV (mk_plus(pn,rn))
280     and p3 = provelt r y
281     and chain = INST [xv |-> xn, yv |-> yn, pv |-> pn,
282                       qv |-> qn, rv |-> rn] modt
283   in
284      MP (MP (MP chain p1) p2) p3
285   end handle HOL_ERR _ => failwith "MOD_CONV"
286            | Div => raise ERR "MOD_CONV" "attempt to take mod 0"
287end;
288
289val _ = Parse.temp_set_grammars ambient_grammars
290
291end
292