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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
open Qed
open Logic
open Lang
open Lang.F
let f_builtin ~library ?(injective=false) ?(result=Real) ?(params=[Real]) ?ext name =
assert (name.[0] == '\\') ;
let call =
match ext with Some call -> call | None ->
String.sub name 1 (String.length name - 1) in
let link = Engine.F_call call in
let category =
let open Qed.Logic in
if injective then Injection else Function
in
let signature = List.map LogicBuiltins.kind_of_tau params in
let params = List.map Kind.of_tau params in
let lfun = extern_s ~library ~category ~result ~params ~link name in
LogicBuiltins.(add_builtin name signature lfun) ; lfun
let f_real_of_int =
extern_f ~library:"qed"
~category:Qed.Logic.Injection
~result:Logic.Real ~params:[Logic.Sint] "real_of_int"
let builtin_real_of_int e =
match F.repr e with
| Qed.Logic.Kint k -> F.e_real (Q.of_bigint k)
| _ -> raise Not_found
let f_truncate = f_builtin ~library:"truncate" ~result:Int "\\truncate"
let f_ceil = f_builtin ~library:"truncate" ~result:Int "\\ceil"
let f_floor = f_builtin ~library:"truncate" ~result:Int "\\floor"
let builtin_truncate f e =
let open Qed.Logic in
match F.repr e with
| Kint _ -> e
| Kreal r when Q.(equal r zero) -> e_zero
| Kreal r ->
begin
try
let truncated = int_of_float (Q.to_float r) in
let reversed = Q.of_int truncated in
let base = F.e_int truncated in
if Q.equal r reversed then base else
if f == f_ceil && Q.(lt zero r) then F.(e_add base e_one) else
if f == f_floor && Q.(lt r zero) then F.(e_sub base e_one) else
base
with _ -> raise Not_found
end
| Fun( f , [e] ) when f == f_real_of_int -> e
| _ -> raise Not_found
let int_of_real x = e_fun f_truncate [x]
let real_of_int x = e_fun f_real_of_int [x]
let int_of_bool a = e_neq a F.e_zero
let bool_of_int a = e_if a F.e_one F.e_zero
let builtin_positive_eq lfun ~domain ~zero ~injective a b =
let open Qed.Logic in
begin match F.repr a , F.repr b with
| Fun(f,[a]) , Fun(f',[b])
when injective && f == lfun && f' == lfun && domain a && domain b ->
e_eq a b
| Fun(f,[a]) , _ when f == lfun && domain a ->
if QED.eval_lt b zero then
e_false
else
if QED.eval_eq zero b then
e_eq a zero
else raise Not_found
| _ -> raise Not_found
end
let builtin_positive_leq lfun ~domain ~zero ~monotonic a b =
let open Qed.Logic in
begin match F.repr a , F.repr b with
| Fun(f,[a]) , Fun(f',[b])
when monotonic && f == lfun && f' == lfun && domain a && domain b ->
e_leq a b
| Fun(f,[a]) , _ when f == lfun && domain a ->
if QED.eval_lt b zero then
e_false
else
if QED.eval_eq zero b then
e_eq a zero
else raise Not_found
| _ , Fun(f,[b]) when f == lfun && domain b && QED.eval_leq a zero ->
e_true
| _ -> raise Not_found
end
let builtin_strict_eq lfun ~domain ~zero ~injective a b =
let open Qed.Logic in
begin match F.repr a , F.repr b with
| Fun(f,[a]) , Fun(f',[b])
when injective && f == lfun && f' == lfun && domain a && domain b ->
e_eq a b
| Fun(f,[a]) , _ when f == lfun && domain a && QED.eval_leq b zero ->
e_false
| _ -> raise Not_found
end
let builtin_strict_leq lfun ~domain ~zero ~monotonic a b =
let open Qed.Logic in
begin match F.repr a , F.repr b with
| Fun(f,[a]) , Fun(f',[b])
when monotonic && f == lfun && f' == lfun && domain a && domain b ->
e_leq a b
| Fun(f,[a]) , _ when f == lfun && domain a && QED.eval_leq b zero ->
e_false
| _ , Fun(f,[b]) when f == lfun && domain b && QED.eval_leq a zero ->
e_true
| _ -> raise Not_found
end
let f_iabs =
extern_f ~library:"cmath" ~link:(Qed.Engine.F_call "IAbs.abs") "\\iabs"
let f_rabs =
extern_f ~library:"cmath"
~result:Real ~params:[Sreal]
~link:(Qed.Engine.F_call "RAbs.abs") "\\rabs"
let () =
begin
LogicBuiltins.(add_builtin "\\abs" [Z] f_iabs) ;
LogicBuiltins.(add_builtin "\\abs" [R] f_rabs) ;
end
let domain_abs _x = true
let builtin_abs f z e =
let open Qed.Logic in
match F.repr e with
| Times(k,a) -> e_times (Integer.abs k) (e_fun f [a])
| Kint k -> e_zint (Integer.abs k)
| Kreal r when Q.lt r Q.zero -> e_real (Q.neg r)
| _ ->
match is_true (e_leq z e) with
| Yes -> e
| No -> e_opp e
| Maybe -> raise Not_found
let builtin_iabs_eq = builtin_positive_eq f_iabs
~domain:domain_abs ~zero:e_zero ~injective:false
let builtin_iabs_leq = builtin_positive_leq f_iabs
~domain:domain_abs ~zero:e_zero ~monotonic:false
let builtin_rabs_eq = builtin_positive_eq f_rabs
~domain:domain_abs ~zero:e_zero_real ~injective:false
let builtin_rabs_leq = builtin_positive_leq f_rabs
~domain:domain_abs ~zero:e_zero_real ~monotonic:false
let f_sqrt = f_builtin ~library:"sqrt" "\\sqrt"
let domain_sqrt x = QED.eval_leq e_zero_real x
let builtin_sqrt e =
let open Qed.Logic in
match F.repr e with
| Kreal r when r == Q.zero -> F.e_zero_real
| Kreal r when r == Q.one -> F.e_one_real
| Mul[a;b] when eval_eq a b ->
e_fun f_rabs [a]
| _ -> raise Not_found
let builtin_sqrt_eq = builtin_positive_eq f_sqrt
~domain:domain_sqrt ~zero:e_zero_real ~injective:true
let builtin_sqrt_leq = builtin_positive_leq f_sqrt
~domain:domain_sqrt ~zero:e_zero_real ~monotonic:true
let f_exp = f_builtin ~library:"exponential" ~injective:true "\\exp"
let f_log = f_builtin ~library:"exponential" "\\log"
let f_log10 = f_builtin ~library:"exponential" "\\log10"
let f_pow = f_builtin ~library:"power" ~params:[Real;Real] "\\pow"
let () = ignore f_log10
let domain_exp _x = true
let domain_log x = QED.eval_lt e_zero_real x
let builtin_exp e =
let open Qed.Logic in
match F.repr e with
| Kreal r when r == Q.zero -> F.e_one_real
| Times(n,r) when n == Z.minus_one ->
F.e_div F.e_one_real (F.e_fun f_exp [r])
| Fun( f , [x] ) when f == f_log && domain_log x ->
x
| _ -> raise Not_found
let builtin_log e =
let open Qed.Logic in
match F.repr e with
| Kreal r when r == Q.one -> F.e_zero_real
| Fun( f , [x] ) when f == f_exp -> x
| Fun( f , [x;n] ) when f == f_pow && domain_log x ->
F.e_mul n (F.e_fun f_log [x])
| _ -> raise Not_found
let builtin_pow a n =
let open Qed.Logic in
match F.repr n with
| Kreal r when Q.(equal r zero) -> F.e_one_real
| Kreal r when Q.(equal r one) -> a
| _ -> raise Not_found
let builtin_exp_eq = builtin_strict_eq f_exp
~domain:domain_exp ~zero:e_zero_real ~injective:true
let builtin_exp_leq = builtin_strict_leq f_exp
~domain:domain_exp ~zero:e_zero_real ~monotonic:true
let f_sin = f_builtin ~library:"trigonometry" "\\sin"
let f_cos = f_builtin ~library:"trigonometry" "\\cos"
let f_tan = f_builtin ~library:"trigonometry" "\\tan"
let f_asin = f_builtin ~library:"arctrigo" "\\asin"
let f_acos = f_builtin ~library:"arctrigo" "\\acos"
let f_atan = f_builtin ~library:"arctrigo" ~injective:true "\\atan"
let domain_asin_acos x =
QED.eval_leq x e_one_real &&
QED.eval_leq e_minus_one_real x
let domain_atan _x = true
let builtin_trigo f_arc ~domain e =
match F.repr e with
| Fun(f,[x]) when f == f_arc && domain x -> x
| _ -> raise Not_found
let () =
begin
ignore (f_builtin ~library:"hyperbolic" "\\sinh") ;
ignore (f_builtin ~library:"hyperbolic" "\\cosh") ;
ignore (f_builtin ~library:"hyperbolic" "\\tanh") ;
end
let () =
begin
ignore (f_builtin ~library:"polar" ~params:[Real;Real] "\\atan2") ;
ignore (f_builtin ~library:"polar" ~params:[Real;Real] "\\hypot") ;
end
let () = Context.register
begin fun () ->
F.set_builtin_1 f_real_of_int builtin_real_of_int ;
F.set_builtin_1 f_truncate (builtin_truncate f_truncate) ;
F.set_builtin_1 f_ceil (builtin_truncate f_ceil) ;
F.set_builtin_1 f_floor (builtin_truncate f_floor) ;
F.set_builtin_1 f_iabs (builtin_abs f_iabs e_zero) ;
F.set_builtin_1 f_rabs (builtin_abs f_rabs e_zero_real) ;
F.set_builtin_eq f_iabs builtin_iabs_eq ;
F.set_builtin_eq f_rabs builtin_rabs_eq ;
F.set_builtin_leq f_iabs builtin_iabs_leq ;
F.set_builtin_leq f_rabs builtin_rabs_leq ;
F.set_builtin_1 f_sqrt builtin_sqrt ;
F.set_builtin_eq f_sqrt builtin_sqrt_eq ;
F.set_builtin_leq f_sqrt builtin_sqrt_leq ;
F.set_builtin_1 f_log builtin_log ;
F.set_builtin_1 f_exp builtin_exp ;
F.set_builtin_eq f_exp builtin_exp_eq ;
F.set_builtin_leq f_exp builtin_exp_leq ;
F.set_builtin_2 f_pow builtin_pow ;
F.set_builtin_1 f_sin (builtin_trigo f_asin ~domain:domain_asin_acos) ;
F.set_builtin_1 f_cos (builtin_trigo f_acos ~domain:domain_asin_acos) ;
F.set_builtin_1 f_tan (builtin_trigo f_atan ~domain:domain_atan) ;
end